手撕代码系列之剑指offer中的典型题目
[toc]
1 数组中重复的数字(03)
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
1 |
|
2 |
|
3 |
|
4 | class Solution { |
5 | |
6 | |
7 | public int findRepeatNumber(int[] nums) { |
8 | for(int i=0;i<nums.length;i++){ |
9 | while(i!=nums[i]){ |
10 | |
11 | if(nums[i]==nums[nums[i]]) |
12 | return nums[i]; |
13 | int temp = nums[i]; |
14 | nums[i]=nums[temp]; |
15 | nums[temp]=temp; |
16 | } |
17 | } |
18 | return 0; |
19 | } |
20 | } |
21 |
|
2 二维数组的查找(04)
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | public boolean findNumberIn2DArray(int[][] matrix, int target) { |
7 | |
8 | if(matrix.length==0) |
9 | return false; |
10 | int row= matrix.length,col = matrix[0].length; |
11 | int i = 0,j=col-1; |
12 | while(i<row&&j>=0){ |
13 | if(matrix[i][j]==target) |
14 | return true; |
15 | else if(matrix[i][j]>target) |
16 | j--; |
17 | else |
18 | i++; |
19 | } |
20 | return false; |
21 | } |
3 从头到尾打印链表(06)
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
1 |
|
2 |
|
3 | public int[] reversePrint(ListNode head) { |
4 | int size = 0; |
5 | ListNode pre = null, cur = head; |
6 | while (cur != null) { |
7 | size++; |
8 | ListNode temp = cur.next; |
9 | cur.next = pre; |
10 | pre = cur; |
11 | cur = temp; |
12 | } |
13 | int i = 0; |
14 | int[] res = new int[size]; |
15 | while (pre != null) { |
16 | res[i++] = pre.val; |
17 | pre = pre.next; |
18 | } |
19 | return res; |
20 | } |
21 |
|
4 重建二叉树(07)
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字
1 |
|
2 |
|
3 | HashMap<Integer, Integer> map = new HashMap<>(); |
4 | public TreeNode buildTree(int[] preorder, int[] inorder) { |
5 | for (int i = 0; i < inorder.length; i++) |
6 | map.put(inorder[i], i); |
7 | return buildTree(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1); |
8 | } |
9 | public TreeNode buildTree(int[] preorder, int pre_L, int pre_R, int[] inorder, int in_L, int in_R) { |
10 | |
11 | if (pre_L > pre_R) return null; |
12 | TreeNode root = new TreeNode(preorder[pre_L]); |
13 | int pivot = map.get(preorder[pre_L]); |
14 | int left_size = pivot - in_L; |
15 | root.left = buildTree(preorder, pre_L + 1, pre_L + left_size, inorder, in_L, pivot - 1); |
16 | root.right = buildTree(preorder, pre_L + left_size + 1, pre_R, inorder, pivot + 1, in_R); |
17 | return root; |
18 | } |
19 |
|
5 两个栈实现一个队列(09)
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
1 |
|
2 |
|
3 | Stack<Integer> A ; |
4 | Stack<Integer> B ; |
5 | public CQueue() { |
6 | A = new Stack<>(); |
7 | B= new Stack<>(); |
8 | } |
9 | public void appendTail(int value) { |
10 | A.push(value); |
11 | } |
12 | public int deleteHead() { |
13 | if(!B.isEmpty()) |
14 | return B.pop(); |
15 | while(!A.isEmpty()) |
16 | B.push(A.pop()); |
17 | return B.isEmpty()?-1: B.pop(); |
18 | } |
19 |
|
6 旋转数组的最小数字
1 | class Solution { |
2 | |
3 | |
4 | |
5 |
|
6 | public int minArray(int[] numbers) { |
7 | int left = 0,right=numbers.length-1; |
8 | while(left<right){ |
9 | int mid =left+(right-left)/2; |
10 | if(numbers[mid]>numbers[right]) |
11 | left=mid+1; |
12 | else if(numbers[mid]<numbers[right]) |
13 | |
14 | right=mid; |
15 | else right--; |
16 | } |
17 | return numbers[left]; |
18 | } |
19 | } |
7 矩阵路径(12)
1 |
|
2 | public boolean exist(char[][] board, String word) { |
3 | char[] words = word.toCharArray(); |
4 | int row = board.length,col = board[0].length; |
5 | for(int i=0;i<row;i++) |
6 | for(int j=0;j<col;j++){ |
7 | if(dfs(board,i,j,words,0)) |
8 | return true; |
9 | } |
10 | return false; |
11 | } |
12 | public boolean dfs(char[][] board,int i,int j,char[] words,int k){ |
13 | |
14 | if(i<0||j<0||i>=board.length||j>=board[0].length||board[i][j]!=words[k]) |
15 | return false; |
16 | |
17 | if(k==words.length-1) |
18 | return true; |
19 | |
20 | char tmp =board[i][j]; |
21 | board[i][j] = '.'; |
22 | boolean flag = dfs(board,i+1,j,words,k+1)||dfs(board,i-1,j,words,k+1)|| |
23 | dfs(board,i,j+1,words,k+1)|| dfs(board,i,j-1,words,k+1); |
24 | board[i][j] = tmp; |
25 | return flag; |
26 | } |
8 机器人运动范围(13)
1 |
|
2 |
|
3 | class Solution { |
4 | boolean[][] visited; |
5 | public int movingCount(int m, int n, int k) { |
6 | visited = new boolean[m][n]; |
7 | return dfs(m, n, k, 0, 0); |
8 | } |
9 | public int dfs(int m, int n, int k, int i, int j) { |
10 | int sum = add(i) + add(j); |
11 | if (i < 0 || i >= m || j < 0 || j >= n || visited[i][j] || sum > k) |
12 | return 0; |
13 | visited[i][j] = true; |
14 | return dfs(m, n, k, i + 1, j) + dfs(m, n, k, i - 1, j) |
15 | + dfs(m, n, k, i, j - 1) + dfs(m, n, k, i, j + 1) + 1; |
16 | } |
17 | public int add(int n) { |
18 | int sum = 0; |
19 | while (n > 0) { |
20 | sum += n % 10; |
21 | n /= 10; |
22 | } |
23 | return sum; |
24 | } |
25 | } |
1 |
|
2 | public int movingCount(int m, int n, int k) { |
3 | Queue<int[]> queue = new LinkedList<>(); |
4 | queue.offer(new int[]{0, 0}); |
5 | int res = 0; |
6 | boolean[][] visited = new boolean[m][n]; |
7 | while (queue.size() > 0) { |
8 | int[] tmp = queue.poll(); |
9 | int i = tmp[0], j = tmp[1]; |
10 | int sum = add(i) + add(j); |
11 | if (i < 0 || i >= m || j < 0 || j >= n || visited[i][j] || sum > k) |
12 | continue; |
13 | res++; |
14 | visited[i][j] = true; |
15 | queue.offer(new int[]{i + 1, j}); |
16 | queue.offer(new int[]{i, j + 1}); |
17 | } |
18 | return res; |
19 | } |
9 剪绳子(14)
1 |
|
2 | class Solution { |
3 | public int cuttingRope(int n) { |
4 | int [] dp =new int[n+1]; |
5 | dp[2]=1; |
6 | for(int i =3;i<=n;i++){ |
7 | for(int j=1;j<=i-1;j++){ |
8 | |
9 | |
10 | |
11 | dp[i] = Math.max(dp[i],Math.max(j*(i-j),j*dp[i-j])); |
12 | } |
13 | } |
14 | return dp[n]; |
15 | } |
16 | } |
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | |
8 | public int cuttingRope(int n) { |
9 | if(n<=3) |
10 | return n-1; |
11 | int k=n/3,b=n%3; |
12 | if(b==0) |
13 | return (int)Math.pow(3,k); |
14 | else if(b==1) |
15 | return (int)Math.pow(3,k-1)*4; |
16 | else |
17 | return (int)Math.pow(3,k)*b; |
18 | } |
19 |
|
20 |
|
10 剪绳子II(14)
1 | |
2 |
|
3 |
|
4 |
|
5 |
|
6 | |
7 | public int cuttingRope(int n) { |
8 | if (n <= 3) |
9 | return n - 1; |
10 | int b = n % 3, k = n / 3 - 1, p = 1000000007; |
11 | long res = 1, a = 3; |
12 | while (k > 0) { |
13 | if ((k & 1) == 1) |
14 | res = (res * a) % p; |
15 | a = (a * a) % p; |
16 | k >>= 1; |
17 | } |
18 | if (b == 0) |
19 | return (int) (res * 3 % p); |
20 | else if (b == 1) |
21 | return (int) (res * 4 % p); |
22 | return (int) (res * 6 % p); |
23 |
|
24 | } |
11 二进制中1的个数(15)
1 | public int hammingWeight(int n) { |
2 | int res =0; |
3 | while(n!=0){ |
4 | |
5 |
|
6 |
|
7 |
|
8 | |
9 | res++; |
10 | n&=(n-1); |
11 | } |
12 | return res; |
13 | } |
12 数值的整数次方(16)
1 |
|
2 |
|
3 |
|
4 |
|
5 | class Solution { |
6 | public double myPow(double x, int n) { |
7 | if(n<0) |
8 | x=1.0/x; |
9 | return func(x,Math.abs(n)); |
10 | } |
11 | public double func(double x,int n){ |
12 | if(n==0) |
13 | return 1.0; |
14 | double half_val = func(x,n/2); |
15 | if(n%2==0) |
16 | return half_val*half_val; |
17 | else |
18 | return x*half_val*half_val; |
19 | } |
20 | } |
1 |
|
2 |
|
3 | public double myPow(double x, int n) { |
4 | long y = n; |
5 | if (n < 0) { |
6 | x = 1 / x; |
7 | y = -y; |
8 | } |
9 | double res = 1.0; |
10 | while (y > 0) { |
11 | if ((y % 2) == 1) |
12 | res *= x; |
13 | x *= x; |
14 | y >>= 1; |
15 | } |
16 | return res; |
17 | } |
13 链表的倒数第k个节点(22)
1 |
|
2 | public ListNode getKthFromEnd(ListNode head, int k) { |
3 | if(head==null||k==0) |
4 | return head; |
5 | ListNode low_node =head,fast_node = head; |
6 | int cur=0; |
7 | while(cur<k){ |
8 | fast_node=fast_node.next; |
9 | cur++; |
10 | } |
11 | while(fast_node!=null){ |
12 | fast_node =fast_node.next; |
13 | low_node =low_node.next; |
14 | } |
15 | return low_node; |
16 | } |
14 反转链表(24)
1 |
|
2 | public ListNode reverseList(ListNode head) { |
3 | if(head==null||head.next==null) return head; |
4 | |
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | ListNode pre =reverseList(head.next); |
13 | head.next.next = head; |
14 | head.next =null; |
15 | return pre; |
16 |
|
17 | } |
15 合并两个有序链表(25)
1 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { |
2 | if(l1==null) return l2; |
3 | if(l2 == null) return l1; |
4 | ListNode head = new ListNode(0); |
5 | ListNode cur =head; |
6 | while(l1!=null&&l2!=null){ |
7 | if(l1.val<l2.val){ |
8 | cur.next =l1; |
9 | cur =l1; |
10 | l1=l1.next; |
11 | } |
12 | else{ |
13 | cur.next =l2; |
14 | cur=l2; |
15 | l2=l2.next; |
16 | } |
17 | } |
18 | if(l1!=null) cur.next=l1; |
19 | if(l2!=null) cur.next=l2; |
20 | return head.next; |
21 | } |
16 树的子结构(26)
1 |
|
2 | public boolean isSubStructure(TreeNode A, TreeNode B) { |
3 | if(B==null||A==null) |
4 | return false; |
5 | if(B.left==null&&B.right==null&&B.val==A.val) |
6 | return true; |
7 | if(B.val!=A.val) return isSubStructure(A.left,B)||isSubStructure(A.right,B); |
8 | boolean match= true; |
9 | if(B.left!=null) |
10 | match&= isSub(A.left,B.left); |
11 | if(B.right!=null) |
12 | match&= isSub(A.right,B.right); |
13 | return match; |
14 | } |
15 | public boolean isSub(TreeNode A,TreeNode B){ |
16 | if(B==null||A==null) |
17 | return false; |
18 | if(B.left==null&&B.right==null&&B.val==A.val) |
19 | return true; |
20 | if(B.val!=A.val) |
21 | return false; |
22 | boolean match= true; |
23 | if(B.left!=null) |
24 | match&= isSub(A.left,B.left); |
25 | if(B.right!=null) |
26 | match&= isSub(A.right,B.right); |
27 | return match; |
28 | } |
1 |
|
2 | public boolean isSubStructure(TreeNode A, TreeNode B) { |
3 | if(B==null||A==null) |
4 | return false; |
5 | return isSub(A,B)||isSubStructure(A.left,B)||isSubStructure(A.right,B); |
6 | } |
7 | public boolean isSub(TreeNode A,TreeNode B){ |
8 | if(B==null) |
9 | return true; |
10 | if(A==null) |
11 | return false; |
12 | return B.val==A.val&&isSub(A.left,B.left)&&isSub(A.right,B.right); |
13 | } |
17 二叉树的镜像(27)
1 |
|
2 | class Solution { |
3 | public TreeNode mirrorTree(TreeNode root) { |
4 | |
5 | if(root==null) |
6 | return null; |
7 | TreeNode left = mirrorTree(root.left); |
8 | TreeNode right = mirrorTree(root.right); |
9 | root.left =right; |
10 | root.right =left; |
11 | return root; |
12 | } |
13 | } |
1 |
|
2 | public TreeNode mirrorTree(TreeNode root) { |
3 | if (root == null) |
4 | return null; |
5 | Queue<TreeNode> queue = new LinkedList<>(); |
6 | queue.offer(root); |
7 | while (!queue.isEmpty()) { |
8 | TreeNode cur_node = queue.poll(); |
9 | |
10 | TreeNode tmp = cur_node.left; |
11 | cur_node.left = cur_node.right; |
12 | cur_node.right = tmp; |
13 | |
14 | if (cur_node.left != null) |
15 | queue.offer(cur_node.left); |
16 | if (cur_node.right != null) |
17 | queue.offer(cur_node.right); |
18 | } |
19 | return root; |
20 | } |
18对称二叉树(28)
1 |
|
2 | public boolean isSymmetric(TreeNode root) { |
3 | return isMirror(root,root); |
4 | } |
5 | public boolean isMirror(TreeNode root1,TreeNode root2){ |
6 | if(root1==null&&root2==null) |
7 | return true; |
8 | if(root1==null||root2==null) |
9 | return false; |
10 | return root1.val==root2.val&& |
11 | isMirror(root1.left,root2.right)&& |
12 | isMirror(root1.right,root2.left); |
13 | } |
1 |
|
2 | public boolean isSymmetric(TreeNode root) { |
3 | if(root==null) |
4 | return true; |
5 | Queue<TreeNode> q =new LinkedList<>(); |
6 | q.offer(root.left); |
7 | q.offer(root.right); |
8 | while(!q.isEmpty()){ |
9 | TreeNode left_node = q.poll(); |
10 | TreeNode right_node =q.poll(); |
11 | if(left_node==null&&right_node==null) |
12 | continue; |
13 | if(left_node==null||right_node==null) |
14 | return false; |
15 | if(left_node.val!=right_node.val) |
16 | return false; |
17 | q.offer(left_node.left); |
18 | q.offer(right_node.right); |
19 | q.offer(left_node.right); |
20 | q.offer(right_node.left); |
21 | } |
22 | return true; |
23 | } |
19 螺旋矩阵(29)
1 | |
2 |
|
3 |
|
4 |
|
5 |
|
6 | public int[] spiralOrder(int[][] matrix) { |
7 | if(matrix.length==0) |
8 | return new int[0]; |
9 | int row = matrix.length,col = matrix[0].length; |
10 | int left = 0,right= matrix[0].length-1,top = 0,down = matrix.length-1; |
11 | |
12 | int [] res =new int[row*col]; |
13 | int index =0; |
14 | while(true){ |
15 | for(int i =left;i<=right;i++) |
16 | res[index++]=matrix[top][i]; |
17 | if(++top>down) break; |
18 | for(int i =top;i<=down;i++) |
19 | res[index++]=matrix[i][right]; |
20 | if(--right<left) break; |
21 | for(int i =right;i>=left;i--) |
22 | res[index++]=matrix[down][i]; |
23 | if(--down<top) break; |
24 | for(int i =down;i>=top;i--) |
25 | res[index++] =matrix[i][left]; |
26 | if(++left>right) break; |
27 | } |
28 | return res; |
29 | } |
20 栈的压入、弹出序列(31)
1 |
|
2 | public boolean validateStackSequences(int[] pushed, int[] popped) { |
3 | if(pushed.length==0) return true; |
4 | Stack<Integer> stack = new Stack<>(); |
5 | int pop = 0; |
6 | |
7 | for(int i=0;i<pushed.length;){ |
8 | if(!stack.isEmpty()&&popped[pop]==stack.peek()){ |
9 | |
10 | stack.pop(); |
11 | pop++; |
12 | } |
13 | else { |
14 | stack.push(pushed[i++]); |
15 | } |
16 | } |
17 | |
18 | while(!stack.isEmpty()){ |
19 | int top =stack.pop(); |
20 | if(top!=popped[pop]) return false; |
21 | pop++; |
22 | } |
23 | return true; |
24 | } |
1 |
|
2 | public boolean validateStackSequences(int[] pushed, int[] popped) { |
3 | if(pushed.length==0) return true; |
4 | Stack<Integer> stack = new Stack<>(); |
5 | int pop = 0; |
6 | for(int i=0;i<pushed.length;i++){ |
7 | stack.push(pushed[i]); |
8 | while(!stack.isEmpty()&&popped[pop]==stack.peek()){ |
9 | |
10 | stack.pop(); |
11 | pop++; |
12 | } |
13 | } |
14 | return stack.isEmpty(); |
15 | } |
21 自上而下打印二叉树III(32)
1 | class Solution { |
2 | |
3 | |
4 | |
5 | public List<List<Integer>> levelOrder(TreeNode root) { |
6 | List<List<Integer>> res = new ArrayList<>(); |
7 | if(root==null) return res; |
8 | Deque<TreeNode> q= new LinkedList<>(); |
9 | q.offer(root); |
10 | int depth=1; |
11 | while(!q.isEmpty()){ |
12 | int size = q.size(); |
13 | List<Integer> tmp =new ArrayList<>(); |
14 | while(size-->0){ |
15 | |
16 | TreeNode tmp_node = (depth%2==0?q.pollFirst():q.pollLast()); |
17 | tmp.add(tmp_node.val); |
18 | if(depth%2==0){ |
19 | if(tmp_node.right!=null) q.offerLast(tmp_node.right); |
20 | if(tmp_node.left!=null) q.offerLast(tmp_node.left); |
21 | } |
22 | else{ |
23 | if(tmp_node.left!=null) q.offerFirst(tmp_node.left); |
24 | if(tmp_node.right!=null) q.offerFirst(tmp_node.right); |
25 | } |
26 | } |
27 | depth++; |
28 | res.add(tmp); |
29 | } |
30 | return res; |
31 | } |
32 | } |
22 二叉搜索树与双向链表(36)
题目描述:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
1 |
|
2 | class Solution { |
3 | Node head=null,tail =null; |
4 | Node pre =null; |
5 | public Node treeToDoublyList(Node root) { |
6 | if(root==null) |
7 | return root; |
8 | inorder(root); |
9 | head.left = tail; |
10 | tail.right = head; |
11 | return head; |
12 | } |
13 | public void inorder(Node root){ |
14 | if(root ==null) return; |
15 | inorder(root.left); |
16 | if(head==null) head = root; |
17 | else{ |
18 | pre.right=root; |
19 | root.left =pre; |
20 | } |
21 | pre =root; |
22 | tail =root; |
23 | inorder(root.right); |
24 | } |
25 | } |
1 |
|
2 | public Node treeToDoublyList(Node root) { |
3 | if (root == null) |
4 | return root; |
5 | Node head = null, tail = null; |
6 | Node cur = root, pre = null; |
7 | Stack<Node> stack = new Stack<>(); |
8 | while (!stack.isEmpty() || cur != null) { |
9 | while (cur != null) { |
10 | stack.push(cur); |
11 | cur = cur.left; |
12 | } |
13 | cur = stack.pop(); |
14 | tail = cur; |
15 | if (head == null) { |
16 | head = cur; |
17 | } else { |
18 | pre.right = cur; |
19 | cur.left = pre; |
20 | } |
21 | pre = cur; |
22 | cur = cur.right; |
23 | } |
24 | head.left = tail; |
25 | tail.right = head; |
26 | return head; |
27 | } |
23 字符串排列(38)
1 |
|
2 |
|
3 |
|
4 |
|
5 | Set<String> res =new HashSet<>(); |
6 | public String[] permutation(String s) { |
7 | boolean[] visited = new boolean[s.length()]; |
8 | String tmp =""; |
9 | dfs(s, 0,tmp, visited); |
10 | return res.toArray(new String[res.size()]); |
11 | } |
12 | public void dfs(String s , int index,String tmp, boolean[] visited) { |
13 | if (index == s.length()) { |
14 | res.add(new String(tmp)); |
15 | return ; |
16 | } |
17 | for (int i = 0; i < s.length(); i++) { |
18 | if (!visited[i]) { |
19 | visited[i] = true; |
20 | tmp+=s.charAt(i); |
21 | dfs(s, index + 1, tmp, visited); |
22 | visited[i] = false; |
23 | tmp =tmp.substring(0,tmp.length()-1); |
24 | } |
25 | } |
26 | } |
24 二叉搜索树的后序遍历
1 |
|
2 | public boolean verifyPostorder(int[] postorder) { |
3 | if(postorder.length<=2) |
4 | return true; |
5 | return verify(postorder,0,postorder.length-1); |
6 | } |
7 | public boolean verify(int[] postorder,int start,int end){ |
8 | if(start>=end) |
9 | return true; |
10 | int cur = start; |
11 | while(cur<=end&&postorder[cur]<postorder[end]) |
12 | |
13 | cur++; |
14 | for(int i=cur;i<=end;i++){ |
15 | if(postorder[i]<postorder[end]) |
16 | return false; |
17 | } |
18 | return verify(postorder,start,cur-1)&&verify(postorder,cur,end-1); |
19 | } |
25 二叉树的最近公共祖先(68)
1 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { |
2 | if(root==null||root==p||root==q) |
3 | return root; |
4 | TreeNode left = lowestCommonAncestor(root.left,p,q); |
5 | TreeNode right = lowestCommonAncestor(root.right,p,q); |
6 | if(left==null) |
7 | return right; |
8 | if(right==null) |
9 | return left; |
10 | return root; |
11 | } |