剑指offer-java
Posted fisherinbox
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指offer-java相关的知识,希望对你有一定的参考价值。
面试题67 机器人的运动范围
题意:
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
解法:回溯法。注意申请的内存要释放掉。delete[] visited;
1 class Solution { 2 public: 3 int movingCount(int threshold, int rows, int cols) 4 { 5 bool *visited = new bool[rows * cols]; 6 for (int i = 0; i < rows * cols; i++) { 7 visited[i] = false; 8 } 9 int count = helper(visited, threshold, 0, 0, rows, cols); 10 delete[] visited; 11 return count; 12 } 13 int helper(bool* visited, int threshold, int i, int j, int rows, int cols) { 14 if (i <0 || j < 0 || i >= rows || j >= cols || visited[i * cols + j]) { 15 return 0; 16 } 17 if (digitSum(i, j) <= threshold) { 18 visited[i * cols + j] = true; 19 int count = 1; 20 count += helper(visited, threshold, i - 1, j, rows, cols); 21 count += helper(visited, threshold, i, j + 1, rows, cols); 22 count += helper(visited, threshold, i + 1, j, rows, cols); 23 count += helper(visited, threshold, i, j - 1, rows, cols); 24 return count; 25 } 26 return 0; 27 } 28 int digitSum(int i, int j) { 29 int sum = 0; 30 while (i / 10 != 0) { 31 sum += i % 10; 32 i = i / 10; 33 } 34 sum += i; 35 while (j / 10 != 0) { 36 sum += j % 10; 37 j = j / 10; 38 } 39 sum += j; 40 return sum; 41 } 42 };
面试题66 判断二维矩阵是否存在一条包含所有字符串的路径。leetcode 79
题意:
Given a 2D board and a word, find if the word exists in the grid. The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once. For example, Given board = [ [\'A\',\'B\',\'C\',\'E\'], [\'S\',\'F\',\'C\',\'S\'], [\'A\',\'D\',\'E\',\'E\'] ] word = "ABCCED", -> returns true, word = "SEE", -> returns true, word = "ABCB", -> returns false.
解法:回溯法也是dfs。
1 class Solution { 2 public: 3 bool exist(vector<vector<char>>& board, string word) { 4 int m = board.size(); 5 int n = board[0].size(); 6 for (int i = 0; i < m; i++) { 7 for (int j = 0; j < n; j++) { 8 if (helper(board, i, j, word, 0)) { 9 return true; 10 } 11 } 12 } 13 return false; 14 } 15 bool helper(vector<vector<char>>& board, int i, int j, string word, int index) { 16 if (i >= board.size() || j >= board[0].size() || i < 0 || j < 0 || board[i][j] == \'#\') { 17 return false; 18 } 19 if (board[i][j] != word.at(index)) { 20 return false; 21 } 22 if (index == word.length() - 1) { 23 return true; 24 } 25 board[i][j] = \'#\'; //去重 26 bool next = helper(board, i - 1, j, word, index + 1) || 27 helper(board, i, j + 1, word, index + 1) || 28 helper(board, i + 1, j, word, index + 1) || 29 helper(board, i, j - 1, word, index + 1); 30 board[i][j] = word.at(index); 31 return next; 32 } 33 };
面试题65 滑动窗口的最大值 leetcode239
题意:给出一个数组和一个滑动窗口大小,返回所有滑动窗口的最大值。
思路:利用双端队列。队列头部始终保存当前滑动窗口的最大值。遍历数组,如果当前数值大于队列尾部数值,则删除所有小于当前数字的队列尾部数字,并在尾部加入当前数值,如果当前数值小于队列尾部,则加入尾部。如果当前索引号与队列头部索引号之差大于等于滑动窗口大小k,则删除头部,因为头部已经不属于当前滑动窗口。注意队列中存的是数值的索引号。
1 class Solution { 2 public: 3 vector<int> maxSlidingWindow(vector<int>& nums, int k) { 4 vector<int> max; 5 if (nums.size() < k || k < 1) { 6 return max; 7 } 8 deque<int> dq; 9 for (int i = 0; i < k; i++) { 10 while (!dq.empty() && nums[i] > nums[dq.back()]) { 11 dq.pop_back(); 12 } 13 dq.push_back(i); 14 } 15 max.push_back(nums[dq.front()]); 16 for (int i = k; i < nums.size(); i++) { 17 while (!dq.empty() && nums[i] >= nums[dq.back()]) { 18 dq.pop_back(); 19 } 20 if (!dq.empty() && dq.front() <= i - k) { 21 dq.pop_front(); 22 } 23 dq.push_back(i); 24 max.push_back(nums[dq.front()]); 25 } 26 return max; 27 } 28 };
面试题64 数据流的实时中位数
思路:用一个最大堆和一个最小堆。将数据流平均分成两个部分,最大堆中的数都小于最小堆中的数,当前数据流个数是偶数的时候,中位数则是最大堆与最小堆堆顶元素之和/2;当前数据流个数是奇数的时候,中位数是最大堆的堆顶。所以当数据流个数是偶数时,最大堆与最小堆数据个数相等,反之,最大堆的数据个数比最小堆多一个。
1.当最大堆与最小堆长度相等时,新来一个数据,本应该加入最大堆,但是如果这个数据比最小堆的最小值要大,就要加入最小堆,再将最小堆的堆顶元素pop出来加入最大堆中。
2.当最大堆长度大于最小堆时,新来一个数据,本应该加入最小堆,但是如果这个数据比最大堆最大值要小,则应该加入最大堆,并且将最大堆的最大值pop加入最小堆。
通过上面两步保证最大堆的所有元素小于最小堆。
插入时间复杂度为O(logn),获取中位数的时间复杂度为O(1);
代码使用c++写的,注意priority_queue的pop函数返回void,并不会返回数值。最小堆的实现没有自定义比较器,而是将数值取负号放入最大堆,相当于形成了一个最小堆。这时候用long类型就比较安全,因为最小负整数加负号之后会越界int的。
1 class MedianFinder { 2 priority_queue<long> small, large; 3 public: 4 /** initialize your data structure here. */ 5 MedianFinder() { 6 7 } 8 9 void addNum(int num) { 10 if (small.size() == large.size()) { 11 if (large.size() != 0 && num > -large.top()) { 12 large.push(-num); 13 small.push(-large.top()); 14 large.pop(); 15 } else { 16 small.push(num); 17 } 18 } 19 if (small.size() > large.size()) { 20 if (num < small.top()) { 21 small.push(num); 22 large.push(- small.top()); 23 small.pop(); 24 } else { 25 large.push(- num); 26 } 27 } 28 } 29 30 double findMedian() { 31 return small.size() > large.size() ? small.top() : (small.top() - large.top()) / 2.0; 32 } 33 }; 34 35 /** 36 * Your MedianFinder object will be instantiated and called as such: 37 * MedianFinder obj = new MedianFinder(); 38 * obj.addNum(num); 39 * double param_2 = obj.findMedian(); 40 */
面试题63 找二叉搜索树的第k大的节点
思路:中序遍历二叉搜索树,非递归的。
1 import java.util.*; 2 /* 3 public class TreeNode { 4 int val = 0; 5 TreeNode left = null; 6 TreeNode right = null; 7 8 public TreeNode(int val) { 9 this.val = val; 10 11 } 12 13 } 14 */ 15 public class Solution { 16 TreeNode KthNode(TreeNode pRoot, int k) 17 { 18 if (pRoot == null || k <= 0) { 19 return null; 20 } 21 Stack<TreeNode> s = new Stack<TreeNode>(); 22 s.push(pRoot); 23 while (!s.isEmpty()) { 24 while (pRoot.left != null) { 25 s.push(pRoot.left); 26 pRoot = pRoot.left; 27 } 28 TreeNode cur = s.pop(); 29 if (--k == 0) { 30 return cur; 31 } 32 if (cur.right != null) { 33 pRoot = cur.right; 34 s.push(pRoot); 35 } 36 } 37 return null; 38 } 39 }
面试题62序列化与反序列化二叉树
思路:采用前序遍历来序列化,相对于之前的层序遍历要简单一点。
1 /* 2 public class TreeNode { 3 int val = 0; 4 TreeNode left = null; 5 TreeNode right = null; 6 7 public TreeNode(int val) { 8 this.val = val; 9 10 } 11 12 } 13 */ 14 public class Solution { 15 String Serialize(TreeNode root) { 16 if (root == null) { 17 return "$"; 18 } 19 StringBuilder s = new StringBuilder(""); 20 SerializeHelper(root, s); 21 s.deleteCharAt(s.length() - 1); 22 return s.toString(); 23 } 24 public void SerializeHelper(TreeNode root, StringBuilder s) { 25 if (root == null) { 26 s.append("$").append(","); 27 return; 28 } 29 s.append(String.valueOf(root.val)).append(","); 30 SerializeHelper(root.left, s); 31 SerializeHelper(root.right, s); 32 } 33 int index = 0; 34 TreeNode Deserialize(String str) { 35 if (str == null || str.length() == 0 || str.charAt(0) == \'$\') { 36 return null; 37 } 38 String[] strs = str.split(","); 39 return DeserializeHelper(strs); 40 } 41 public TreeNode DeserializeHelper(String[] strs) { 42 if (strs[index].equals("$")) { 43 index++; 44 return null; 45 } else { 46 TreeNode node = new TreeNode(Integer.valueOf(strs[index])); 47 index++; 48 node.left = DeserializeHelper(strs); 49 node.right = DeserializeHelper(strs); 50 return node; 51 } 52 } 53 }
面试题61 之字形打印树
思路:双栈,两个栈分别保存偶数层和奇数层的(0开始)。偶数层的节点的下一层从左到右保存到奇数层,奇数层的下一层的节点从右到左保存到偶数层。
注意:之前的做法是用ArrayList.add(0,element)来实现,这个方法源代码是需要内存复制的,效率应该会比较低
1.java
1 import java.util.ArrayList; 2 import java.util.*; 3 /* 4 public class TreeNode { 5 int val = 0; 6 TreeNode left = null; 7 TreeNode right = null; 8 9 public TreeNode(int val) { 10 this.val = val; 11 12 } 13 14 } 15 */ 16 public class Solution { 17 public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) { 18 if (pRoot == null) { 19 return new ArrayList<>(); 20 } 21 ArrayList<ArrayList<Integer> > ans = new ArrayList<>(); 22 Stack<TreeNode> s1 = new Stack<>(); 23 Stack<TreeNode> s2 = new Stack<>(); 24 boolean curLevel = true; 25 s1.push(pRoot); 26 while (!s1.isEmpty() || !s2.isEmpty()) { 27 ArrayList<Integer> level = new ArrayList<>(); 28 if (curLevel) { 29 while (!s1.isEmpty()) { 30 TreeNode cur = s1.pop(); 31 level.add(cur.val); 32 if (cur.left != null) { 33 s2.push(cur.left); 34 } 35 if (cur.right != null) { 36 s2.push(cur.right); 37 } 38 } 39 } else { 40 while (!s2.isEmpty()) { 41 TreeNode cur = s2.pop(); 42 level.add(cur.val); 43 if (cur.right != null) { 44 s1.push(cur.right); 45 } 46 if (cur.left != null) { 47 s1.push(cur.left); 48 } 49 } 50 } 51 ans.add(level); 52 curLevel = !curLevel; 53 } 54 return ans; 55 } 56 57 }
2.c++
1 /* 2 struct TreeNode { 3 int val; 4 struct TreeNode *left; 5 struct TreeNode *right; 6 TreeNode(int x) : 7 val(x), left(NULL), right(NULL) { 8 } 9 }; 10 */ 11 class Solution { 12 public: 13 vector<vector<int>> Print(TreeNode* pRoot) { 14 vector<vector<int>> result; 15 if (pRoot == NULL) { 16 return result; 17 } 18 stack<TreeNode*> s[2]; 19 int cur = 0; 20 s[cur].push(pRoot); 21 struct TreeNode* node; 22 while (!s[0].empty() || !s[1].empty()) { 23 vector<int> level; 24 while (!s[cur].empty()) { 25 node = s[cur].top(); 26 s[cur].pop(); 27 level.push_back(node->val); 28 if (cur == 0) { 29 if (node->left != NULL) { 30 s[1].push(node->left); 31 } 32 if (node->right != NULL) { 33 s[1].push(node->right); 34 } 35 } 36 if (cur == 1) { 37 if (node->right != NULL) { 38以上是关于剑指offer-java的主要内容,如果未能解决你的问题,请参考以下文章