算是大概完成了这个学期初定下的目标,终于刷完了剑指offer的题目,尽管刷了一遍之后感觉自己大部分又忘记了,很明显又要再刷一遍,因此在此再立下一个小目标,在放假前将剑指offer二刷一半吧!!!这个博客就重新将之前做的剑指offer题目整理一下,感觉之前写的太乱了,就算是自己看,感觉以后也不舒服。
1.Interview Flow
9. Fizz Buzz(思路:分别除3除5能否整除做操作)
1 class Solution { 2 public ArrayList<String> fizzBuzz(int n) { 3 ArrayList<String> result = new ArrayList<>(); 4 if (n <= 0) { 5 return result; 6 } 7 for (int i = 1; i <= n; i++) { 8 if (i % 3 == 0 && i % 5 != 0) { 9 result.add("fizz"); 10 } else if (i % 5 == 0 && i % 3 != 0) { 11 result.add("buzz"); 12 } else if (i % 3 == 0 && i % 5 == 0) { 13 result.add("fizz buzz"); 14 } else { 15 //result.add(i + ""); 16 //result.add(Integer.toString(i)); 17 result.add(String.valueOf(i)); 18 } 19 } 20 return result; 21 } 22 }
2.Basic Knowledge
366. Fibonacci (思路:根据 f(0)和f(1)计算出f(2), 进而计算f(3)、f(4)等等,递归会出现TLE错误)
1 class Solution { 2 public int fibonacci(int n) { 3 // if (n <= 0) { 4 // return 0; 5 // } 6 // //wrong solution: we don't know the value of n, so fib[0] = 0 is wrong!!! 7 // int[] fib = new int[n]; 8 // fib[0] = 0; 9 // fib[1] = 1; 10 // for (int i = 2; i < n; i++) { 11 // fib[i] = fib[i - 1] + fib[i - 2]; 12 // } 13 // return fib[n - 1]; 14 int fib1 = 0; 15 int fib2 = 1; 16 int sum = 0; 17 if (n == 1) { 18 return 0; 19 } 20 if (n == 2) { 21 return 1; 22 } 23 for (int i = 3; i <= n; i++) { 24 sum = fib1 + fib2; 25 fib1 = fib2; 26 fib2 = sum; 27 } 28 return sum; 29 } 30 }
class Solution { //单例模式三个要素:①只有一个实例②必须自己创建这个实例③可以向外部提供这个实例 //对应的程序:①私有的构造函数保证只有一个实例②类定义中含有一个私有的静态类对象 //③公有的函数可以获取这个对象 //懒汉模式 /**private Solution() {} private static Solution instance = null; public static Solution getInstance() { if (instance == null) { instance = new Solution(); } return instance; }*/ //饿汉模式 /**private Solution() {} private static Solution instance = new Solution(); public static Solution getInstance() { return instance; }*/ //加锁双重检查 private Solution() {} private static Solution instance = null; public static Solution getInstance() { if (instance == null) { synchronized (Solution.class) { if (instance == null) { instance = new Solution(); } } } return instance; } }
111. Climbing Stairs(思路:找规律,分别算出前几级发现规律跟Fibonacii一样)
1 public class Solution { 2 public int climbStairs(int n) { 3 //we have to find the law of this problem 4 //1(1) 2(2) 3(3) 4(5) 5(8) 6(13) 5 //a1 + a2 = a3 6 //a2 + a3 = a4 7 if (n <= 1) { 8 return 1; 9 } 10 int c1 = 1; 11 int c2 = 2; 12 if (n == 2) { 13 return 2; 14 } 15 int sum = 0; 16 for (int i = 3; i <= n; i++) { 17 sum = c1 + c2; 18 c1 = c2; 19 c2 = sum; 20 } 21 return sum; 22 } 23 }
204. Singleton(思路:①私有的构造函数保证只有一个实例②类定义中含有一个私有的静态类对象③公有的函数可以获取这个对象)
1 class Solution { 2 //单例模式三个要素:①只有一个实例②必须自己创建这个实例③可以向外部提供这个实例 3 //对应的程序:①私有的构造函数保证只有一个实例②类定义中含有一个私有的静态类对象 4 //③公有的函数可以获取这个对象 5 private Solution() { 6 } 7 8 private static Solution instance = null; 9 10 public static Solution getInstance() { 11 // if (instance == null) { 12 // instance = new Solution(); 13 // } 14 // return instance; 15 return instance; 16 } 17 }
212. Space Replacement (思路:由于必须对字符数组本身进行操作,因此可以先通过空格个数计算新字符数组总长度,然后从后向前进行复制,以确保字符不会被覆盖)
1 public class Solution { 2 public int replaceBlank(char[] str, int length) { 3 if (str == null || str.length <= 0) { 4 return 0; 5 } 6 //this problem needs to be processed in-place, so we should process the 7 //"str" itself, so we can copy from the end of new "str" 8 int numOfSpace = 0; 9 for (int i = 0; i < str.length; i++) { 10 if (str[i] == ' ') { 11 numOfSpace++; 12 } 13 } 14 int newLen = length + numOfSpace * 2; 15 int i = length - 1; 16 int j = newLen - 1; 17 while (i >= 0 && j >= 0) { 18 if (str[i] == ' ') { 19 str[j] = '0'; 20 j--; 21 str[j] = '2'; 22 j--; 23 str[j] = '%'; 24 j--; 25 i--; 26 } else { 27 str[j] = str[i]; 28 j--; 29 i--; 30 } 31 } 32 return newLen; 33 } 34 }
365. Count 1 in Binary (思路:把一个整数减一,再和原来的整数做与操作,会把该整数最右边的一个1变为0,因此一个整数有多少个1,便可以进行多少次这样的操作)
1 public class Solution { 2 public int countOnes(int num) { 3 //(1100)&(1100 - 1 = 1011) = (1000) 4 //把一个整数减一,再和原来的整数做与操作,会把该整数最右边的一个1变为0, 5 //因此一个整数有多少个1,便可以进行多少次这样的操作 6 int numOfOne = 0; 7 while (num != 0) { 8 numOfOne++; 9 num = num & (num - 1); 10 } 11 return numOfOne; 12 } 13 }
35. Reverse Linked List(思路:定义两个指针,分别指向当前节点和前一节点,因此只需要将cur.next = pre就行了,但是要注意保存cur.next)
1 public class Solution { 2 public ListNode reverse(ListNode head) { 3 if (head == null || head.next == null) { 4 return head; 5 } 6 //define two points, pre and cur point to the current node and the node 7 //before current node, so let cur.next = pre; 8 ListNode pre = null; 9 ListNode cur = head; 10 while (cur != null) { 11 ListNode next = cur.next; 12 // this code is used to save cur.next, because node will be 13 //moved backward, but it has been changed. 14 cur.next = pre; 15 pre = cur; 16 cur = next; 17 } 18 return pre; 19 } 20 }
36. Reverse Linked List II (思路:分三步,第一保存mNode和它之前的节点,第二步从mNode到nNode反转,第三步保存nNode,并将链表连接起来)
1 public class Solution { 2 public ListNode reverseBetween(ListNode head, int m , int n) { 3 if (head == null || head.next == null || m >= n) { 4 return head; 5 } 6 //Three Steps 7 ListNode dummy = new ListNode(0); 8 dummy.next = head; 9 ListNode cur = dummy; 10 //Step1: find and save mNode and the node before mNode 11 for (int i = 1; i < m; i++) { 12 cur = cur.next; 13 } 14 ListNode mPre = cur; 15 ListNode mNode = cur.next; 16 //Step2: reverse the list from mNode to nNode 17 ListNode pre = cur.next; 18 cur = pre.next; 19 for (int i = m; i < n; i++) { 20 ListNode next = cur.next; 21 cur.next = pre; 22 pre = cur; 23 cur = next; 24 } 25 //Step3: save the nNode and link the list again 26 ListNode nNode = pre; 27 ListNode nNext = cur; 28 mPre.next = nNode; 29 mNode.next = nNext; 30 return dummy.next; 31 } 32 }
28. Search a 2D Matrix(思路: 把target跟右上角的数相比,如果小于右上角,去前一列,如果大于,去后一行)
1 public class Solution { 2 public boolean searchMatrix(int[][] matrix, int target) { 3 //compare target and number of top right corner, 4 //if target < matrix[top right corner], then the column-- 5 //if target > matrix[rop right corner], then the row++ 6 if (matrix == null || matrix.length == 0) { 7 return false; 8 } 9 if (matrix[0] == null || matrix[0].length == 0) { 10 return false; 11 } 12 13 int row = matrix.length; 14 int column = matrix[0].length; 15 int i = 0; 16 int j = column - 1; 17 18 while (i < row && j >= 0) { 19 if (target > matrix[i][j]) { 20 i++; 21 } else if (target < matrix[i][j]) { 22 j--; 23 } else { 24 return true; 25 } 26 } 27 return false; 28 } 29 }
38. Search a 2D Matrix II(思路:同上,注意如果target找到,注意更换行和列,否则会死循环)
1 public class Solution { 2 public int searchMatrix(int[][] matrix, int target) { 3 //it is the same as the solution of "search a 2D Matrix" 4 //but we should notice that 21 line and 22 line, after targetNum++, the 5 //row and column should be changed 6 int targetNum = 0; 7 if (matrix == null || matrix.length == 0) { 8 return targetNum; 9 } 10 if (matrix[0] == null || matrix[0].length == 0) { 11 return targetNum; 12 } 13 14 int row = matrix.length; 15 int column = matrix[0].length; 16 int i = 0; 17 int j = column - 1; 18 19 while (i < row && j >= 0) { 20 if (target == matrix[i][j]) { 21 targetNum++; 22 j--; 23 i++; 24 } else if (target < matrix[i][j]) { 25 j--; 26 } else { 27 i++; 28 } 29 } 30 return targetNum; 31 } 32 }
159. Find Minimum in Rotated Sorted Array(思路: 二分查找,用nums[right] 与 nums[mid]比较,这样对数组没有旋转的情况也适用,注意nums[right] > nums[mid]的特殊处理)
1 public class Solution { 2 public int findMin(int[] nums) { 3 //Example : (4 5 6 7 0 1 2) (5 0 1 2 3 4) 4 //compare nums[right] and nums[mid] (we don't compare nums[left] and nums[mid], 5 //because it doesn't the instance of (0 1 2 3 4 5), which the array is 6 //not rotated) if "nums[right] < nums[mid]" means the target is in the 7 //right part, then "left = mid + 1" (notice that "left = mid" is wrong) 8 //else the target is in the left part 9 if (nums == null || nums.length == 0) { 10 return 0; 11 } 12 13 int left = 0; 14 int right = nums.length - 1; 15 16 while (left < right) { 17 int mid = left + (right - left) / 2; 18 if (nums[right] < nums[mid]) { 19 left = mid + 1; 20 } else { 21 right = mid; 22 } 23 } 24 return nums[right]; 25 } 26 }
160. Find Minimum in Rotated Sorted Array II (思路:有重复数字时,需要对相等的情况进行处理,就是nums[right] == nums[left],操作是"right--")
1 public class Solution { 2 public int findMin(int[] nums) { 3 //it is the same as "Find Minimum in Rotated Sorted Array " 4 //but we should notice that if duplicates exist, we should do "right--" 5 if (nums == null || nums.length == 0) { 6 return 0; 7 } 8 9 int left = 0; 10 int right = nums.length - 1; 11 12 while (left < right) { 13 int mid = left + (right - left) / 2; 14 if (nums[right] > nums[mid]) { 15 right = mid; 16 } else if (nums[right] < nums[mid]) { 17 left = mid + 1; 18 } else { 19 right--; 20 } 21 } 22 return nums[right]; 23 } 24 }
40. Implement Queue by Two Stacks (思路: 将新来的数字压入栈1,从栈2中进行pop和top操作,举个实际的例子说明更易理解)
1 public class MyQueue { 2 Stack<Integer> stack1; 3 Stack<Integer> stack2; 4 //notice the importance of "stack1ToStack2", push the element to stack1, and 5 //pop and top the element from stack2 6 public MyQueue() { 7 stack1 = new Stack<>(); 8 stack2 = new Stack<>(); 9 } 10 11 private void stack1ToStack2() { 12 while (!stack1.isEmpty()) { 13 stack2.push(stack1.pop()); 14 } 15 } 16 17 public void push(int num) { 18 stack1.push(num); 19 } 20 21 public int pop() { 22 if (stack2.isEmpty()) { 23 stack1ToStack2(); 24 } 25 return stack2.pop(); 26 } 27 28 public int top() { 29 if (stack2.isEmpty()) { 30 stack1ToStack2(); 31 } 32 return stack2.peek(); 33 } 34 }
72. Construct Binary Tree from Inorder and Postorder Traversal (思路: 首先根据后序遍历中的根节点(最后一个数字)从中序遍历中找出其位置,利用这个位置作为递归辅助函数的参数,然后先建立左子树,再建立右子树)
1 public class Solution { 2 public TreeNode buildTree(int[] inorder, int[] postorder) { 3 if (inorder.length != postorder.length) { 4 return null; 5 } 6 return buildTreeHelper(inorder, 0, inorder.length - 1, postorder, 0, postorder.length - 1); 7 } 8 //build root, build the left tree, build the right tree, notice the importance of parameters 9 public TreeNode buildTreeHelper(int[] inorder, int inStart, int inEnd, int[] postorder, int postStart, int postEnd) { 10 if (inStart > inEnd) { 11 return null; 12 } 13 TreeNode root = new TreeNode(postorder[postEnd]); 14 int rootIndex = findRoot(inorder, root.val); 15 root.left = buildTreeHelper(inorder, inStart, rootIndex - 1, postorder, postStart, postStart + (rootIndex - inStart) - 1); 16 root.right = buildTreeHelper(inorder, rootIndex + 1, inEnd, postorder, postStart + (rootIndex - inStart), postEnd - 1); 17 return root; 18 } 19 //find the position of root in Inorder traversal 20 private int findRoot(int[] inorder, int root) { 21 if (inorder == null || inorder.length == 0) { 22 return -1; 23 } 24 int rootIndex = 0; 25 for (int i = 0; i < inorder.length; i++) { 26 if (root == inorder[i]) { 27 rootIndex = i; 28 } 29 } 30 return rootIndex; 31 } 32 }
73. Construct Binary Tree from Preorder and Inorder Traversal (思路:首先根据前序遍历中的根节点(第一个数字)从中序遍历中找出其位置,利用这个位置作为递归辅助函数的参数,然后先建立左子树,再建立右子树)
public class Solution { public TreeNode buildTree(int[] preOrder, int[] inOrder) { if (preOrder.length != inOrder.length) { return null; } return buildTreeHelper(preOrder, 0, preOrder.length - 1, inOrder, 0, inOrder.length - 1); } //build root, build the left tree, build the right tree, notice the importance of parameters public TreeNode buildTreeHelper(int[] preOrder, int preStart, int preEnd, int[] inOrder, int inStart, int inEnd) { if (preStart > preEnd || inStart > inEnd) { return null; } TreeNode root = new TreeNode(preOrder[preStart]); int rootIndex = findRoot(inOrder, root.val); root.left = buildTreeHelper(preOrder, preStart + 1, preStart + (rootIndex - inStart), inOrder, inStart, rootIndex - 1); root.right = buildTreeHelper(preOrder, preStart + (rootIndex - inStart) + 1, preEnd, inOrder, rootIndex + 1, inEnd); return root; } //find the position of root in Inorder traversal public int findRoot(int[] inOrder, int root) { int rootIndex = 0; for (int i = 0; i < inOrder.length; i++) { if (root == inOrder[i]) { rootIndex = i; } } return rootIndex; } }
3. Coding Quality
373. Partition Array by Odd and Even (思路: 双指针,考虑到可扩展性,把判断部分写成子函数)
1 public class Solution { 2 public void partitionArray(int[] nums) { 3 //an easy problem using twoPoints to solve 4 //line 17 is very important, it can process the instance of the array 5 //that has been processed (1 3 5 2 4 6) 6 if (nums == null || nums.length == 0) { 7 return; 8 } 9 int left = 0; 10 int right = nums.length - 1; 11 while (left < right) { 12 while (!divideFun(nums[left])) { 13 left++; 14 } 15 while (divideFun(nums[right])) { 16 right--; 17 } 18 if (left < right) { 19 int temp = nums[left]; 20 nums[left] = nums[right]; 21 nums[right] = temp; 22 } 23 } 24 } 25 public boolean divideFun(int num) { 26 if (num % 2 == 0) { 27 return true; 28 } 29 return false; 30 } 31 }
372. Delete Node in the Middle of Singly Linked List(思路: 改变node的值以及next, node.val = node.next.val node.next = node.next.next)
1 /** 2 * Definition for ListNode. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int val) { 7 * this.val = val; 8 * this.next = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 public void deleteNode(ListNode node) { 14 if (node == null) { 15 return; 16 } 17 //change the value of node and the next of node; 18 node.val = node.next.val; 19 node.next = node.next.next; 20 } 21 }
245. Subtree (思路:开始注意考虑所有可能为空的情况。一个函数用于判断两个树是否相同,然后先判断树1是否与树2相同,如果不同,再判断以树1左节点或者右节点为根节点的树是否与树2相同)
1 /** 2 * Definition of TreeNode: 3 * public class TreeNode { 4 * public int val; 5 * public TreeNode left, right; 6 * public TreeNode(int val) { 7 * this.val = val; 8 * this.left = this.right = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /** 14 * @param T1, T2: The roots of binary tree. 15 * @return: True if T2 is a subtree of T1, or false. 16 */ 17 public boolean isSubtree(TreeNode root1, TreeNode root2) { 18 //a difficult problem! we have to consider all instances 19 //line 20 must be judged first!!! 20 if (root2 == null) { 21 return true; 22 } 23 if (root1 == null) { 24 return false; 25 } 26 if(isEqual(root1, root2)) { 27 return true; 28 } 29 return isSubtree(root1.left, root2) || isSubtree(root1.right, root2); 30 } 31 public boolean isEqual(TreeNode root1, TreeNode root2) { 32 //the function is to judge if two trees are equal! 33 if (root1 == null || root2 == null) { 34 //nice code!!! 35 return root1 == root2; 36 } 37 if (root1.val != root2.val) { 38 return false; 39 } 40 return isEqual(root1.left, root2.left) && isEqual(root1.right, root2.right); 41 } 42 }
174. Remove Nth Node From End of List (思路: 定义快慢两个指针, 快指针先走n步, 然后两个指针一起走直到快指针到头,此时慢指针指向要删除节点的前一节点)
1 /** 2 * Definition for ListNode. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int val) { 7 * this.val = val; 8 * this.next = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /** 14 * @param head: The first node of linked list. 15 * @param n: An integer. 16 * @return: The head of linked list. 17 */ 18 ListNode removeNthFromEnd(ListNode head, int n) { 19 //define two points slow and fast, fast move forward n steps, move slow 20 //and fast until fast.next == null, then slow points to the node that 21 //we need. 22 if (head == null || n < 1) { 23 return null; 24 } 25 26 ListNode dummy = new ListNode(0); 27 dummy.next = head; 28 ListNode fast = dummy; 29 30 for (int i = 0; i < n; i++) { 31 fast = fast.next; 32 } 33 34 ListNode slow = dummy; 35 while (fast.next != null) { 36 fast = fast.next; 37 slow = slow.next; 38 } 39 40 slow.next = slow.next.next; 41 42 return dummy.next; 43 } 44 }
165. Merge Two Sorted Lists (思路: 递归做法,比较两个头的值,较小的就是下一节点)
1 /** 2 * Definition for ListNode. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int val) { 7 * this.val = val; 8 * this.next = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /** 14 * @param ListNode l1 is the head of the linked list 15 * @param ListNode l2 is the head of the linked list 16 * @return: ListNode head of linked list 17 */ 18 public ListNode mergeTwoLists(ListNode head1, ListNode head2) { 19 //notice line 22 , if the code is "else" , it is wrong, line 25 can't be 20 //reached, line 21 to line 24 must be returned 21 if (head1 == null) { 22 return head2; 23 } else if (head2 == null){ 24 return head1; 25 } 26 27 ListNode mergeHead = null; 28 29 if (head1.val < head2.val) { 30 mergeHead = head1; 31 mergeHead.next = mergeTwoLists(head1.next, head2); 32 } else { 33 mergeHead = head2; 34 mergeHead.next = mergeTwoLists(head1, head2.next); 35 } 36 return mergeHead; 37 } 38 }
371. Print Numbers by Recursion(比较难想到的题目,Mark一下)
1 public class Solution { 2 /** 3 * @param n: An integer. 4 * return : An array storing 1 to the largest number with n digits. 5 */ 6 public List<Integer> numbersByRecursion(int n) { 7 List<Integer> result = new ArrayList<>(); 8 if (n <= 0) { 9 return result; 10 } 11 recursion(n, 0, result); 12 return result; 13 } 14 //the definition of recursion 15 public void recursion(int n, int num, List<Integer> result) { 16 //the exit of recursion 17 if (n == 0) { 18 if (num > 0) { 19 result.add(num); 20 } 21 return; 22 } 23 //the dismantling of recursion 24 for (int i = 0; i < 10; i++) { 25 recursion(n - 1, num * 10 + i, result); 26 } 27 } 28 }
140. Fast Power (比较难想到的题目,Mark一下)
1 class Solution { 2 public int fastPower(int a, int b, int n) { 3 //the exit of recursion 4 if (n == 0) { 5 return 1 % b; 6 } 7 if (n == 1) { 8 return a % b; 9 } 10 //the definition of recursion 11 long result = fastPower(a, b, n / 2); 12 //long result = fastPower(a, b, n >> 1); 13 //the dismantling of recursion 14 result = (result * result) % b; 15 if (n % 2 == 1) { 16 result = (result * a) % b; 17 } 18 return (int) result; 19 } 20 }
376. Binary Tree Path Sum(思路: 定义一个递归函数对树进行前序遍历,直到到达叶节点,此时,不管符不符合要求,都退回父节点,对树的另一侧进行相同的操作)
1 /** 2 * Definition of TreeNode: 3 * public class TreeNode { 4 * public int val; 5 * public TreeNode left, right; 6 * public TreeNode(int val) { 7 * this.val = val; 8 * this.left = this.right = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /** 14 * @param root the root of binary tree 15 * @param target an integer 16 * @return all valid paths 17 */ 18 public List<List<Integer>> binaryTreePathSum(TreeNode root, int target) { 19 List<List<Integer>> result = new ArrayList<>(); 20 if (root == null) { 21 return result; 22 } 23 List<Integer> tempList = new ArrayList<>(); 24 recHelper(result, tempList, root, target); 25 return result; 26 } 27 public void recHelper(List<List<Integer>> result, List<Integer> tempList, TreeNode root, int target) { 28 //递归函数的作用可以理解为:一直在前序遍历树直到叶节点 29 tempList.add(root.val); 30 //current node is the leaf node 31 if (root.left == null && root.right == null) { 32 if (root.val == target) { 33 result.add(new ArrayList<Integer>(tempList)); 34 } 35 return; 36 } 37 if (root.left != null) { 38 recHelper(result, tempList, root.left, target - root.val); 39 //递归的思路一般比较难理解,如果程序已经运行到这里,说明已经找到一条合适的路径例如(1,2,2),或者是已经到达叶节点单仍然没有找到合适的路径,因此下一步需要退回到父节点寻找下一跳合适的路径 40 tempList.remove(tempList.size() - 1); 41 } 42 if (root.right != null) { 43 recHelper(result, tempList, root.right, target - root.val); 44 tempList.remove(tempList.size() - 1); 45 } 46 } 47 }
/** * Definition of TreeNode: * public class TreeNode { * public int val; * public TreeNode left, right; * public TreeNode(int val) { * this.val = val; * this.left = this.right = null; * } * } */ public class Solution { /** * @param root the root of binary tree * @param target an integer * @return all valid paths */ //递归函数需要有个临时链表作为参数,用于保存当前遍历的值,递归出口定义时,只要到达叶节点切记返回,递归出去了,说明到达了叶节点,此时需要返回父节点,继续从另一侧进行判断 public List<List<Integer>> binaryTreePathSum(TreeNode root, int target) { List<List<Integer>> result = new ArrayList(); if (root == null) { return result; } List<Integer> tempList = new ArrayList<>(); recHelper(result, tempList, root, target); return result; } public void recHelper(List<List<Integer>> result, List<Integer> tempList, TreeNode root, int target) { //递归出口:(首先注意题目要求:路径一定是从根节点到叶节点的路径,当遍历到叶节点的时候不管符不符合target要求,必然返回,跳出当前递归,防止死循环) tempList.add(root.val); if (root.left == null && root.right == null) { if (root.val == target) { result.add(new ArrayList<Integer>(tempList)); } return; } if (root.left != null) { recHelper(result, tempList, root.left, target - root.val); //从这里开始进入递归,不断递归直到出递归,运行到这里,说明必然到达了叶节点,此时返回父节点开始判断右子节点是否满足,并且临时链表除去左子节点的值 tempList.remove(tempList.size() - 1); } if (root.right != null) { recHelper(result, tempList, root.right, target - root.val); tempList.remove(tempList.size() - 1); } } }
375. Clone Binary Tree (思路:简单的递归问题,先复制左子树 ,然后复制右字树)
1 /** 2 * Definition of TreeNode: 3 * public class TreeNode { 4 * public int val; 5 * public TreeNode left, right; 6 * public TreeNode(int val) { 7 * this.val = val; 8 * this.left = this.right = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /** 14 * @param root: The root of binary tree 15 * @return root of new tree 16 */ 17 public TreeNode cloneTree(TreeNode root) { 18 //easy problem of recursion 19 if (root == null) { 20 return root; 21 } 22 TreeNode newRoot = new TreeNode(root.val); 23 newRoot.left = cloneTree(root.left); 24 newRoot.right = cloneTree(root.right); 25 return newRoot; 26 } 27 }
211. String Permutation(思路: 利用字符的ackii码,定义一个数组用以字符ackii码的形式记录源字符串中字符出现的次数,再对目标字符串进行遍历,同样的方式,只不过变成数字减一,最后判断数组是不是全为0就行)
1 public class Solution { 2 /** 3 * @param A a string 4 * @param B a string 5 * @return a boolean 6 */ 7 public boolean stringPermutation(String a, String b) { 8 if (a.length() != b.length()) { 9 return false; 10 } 11 int[] temp = new int[1000]; 12 for (int i = 0; i < a.length(); i++) { 13 temp[(int) a.charAt(i)] += 1; 14 } 15 for (int i = 0; i < b.length(); i++) { 16 temp[(int) b.charAt(i)] -= 1; 17 } 18 for (int i = 0; i < a.length(); i++) { 19 if (temp[i] != 0) { 20 return false; 21 } 22 } 23 return true; 24 } 25 }
public class Solution { /** * @param A a string * @param B a string * @return a boolean */ public boolean Permutation(String a, String b) { //注意如何将字符转化为ackii码(直接强制转换),以及判断整个数组是否为0(遍历) if (a == null || b == null) { return a == b; } if (a.length() != b.length()) { return false; } int[] nums = new int[150]; for (int i = 0; i < a.length(); i++) { nums[(int)a.charAt(i)]++; } for (int i = 0; i < b.length(); i++) { nums[(int)b.charAt(i)]--; } for (int i = 0; i < nums.length; i++) { if (nums[i] != 0) { return false; } } return true; } }
4. Thought of Solution
69. Binary Tree Level Order Traversal(思路:举个例子就会发现,这是一个先入先出的过程,因此定义一个队列,注意队列的大小就是当前深度的节点数目)
1 /** 2 * Definition of TreeNode: 3 * public class TreeNode { 4 * public int val; 5 * public TreeNode left, right; 6 * public TreeNode(int val) { 7 * this.val = val; 8 * this.left = this.right = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /** 14 * @param root: The root of binary tree. 15 * @return: Level order a list of lists of integer 16 */ 17 public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) { 18 ArrayList<ArrayList<Integer>> result = new ArrayList<>(); 19 if (root == null) { 20 return result; 21 } 22 23 //queue is an interface, and it can be implmented by LinkedList 24 Queue<TreeNode> queue = new LinkedList<>(); 25 queue.offer(root); 26 27 while (!queue.isEmpty()) { 28 29 ArrayList<Integer> level = new ArrayList<>(); 30 // the queueSize is the number of node of this level 31 int queueSize = queue.size(); 32 33 for (int i = 0; i < queueSize; i++) { 34 35 TreeNode head = queue.poll(); 36 level.add(head.val); 37 38 if (head.left != null) { 39 queue.offer(head.left); 40 } 41 if (head.right != null) { 42 queue.offer(head.right); 43 } 44 } 45 result.add(level); 46 } 47 return result; 48 } 49 }
70. Binary Tree Level Order Traversal II (思路: 同上,只需要最后将链表反转就行了)
1 /** 2 * Definition of TreeNode: 3 * public class TreeNode { 4 * public int val; 5 * public TreeNode left, right; 6 * public TreeNode(int val) { 7 * this.val = val; 8 * this.left = this.right = null; 9 * } 10 * } 11 */ 12 13 14 public class Solution { 15 /** 16 * @param root: The root of binary tree. 17 * @return: buttom-up level order a list of lists of integer 18 */ 19 public ArrayList<ArrayList<Integer>> levelOrderBottom(TreeNode root) { 20 ArrayList<ArrayList<Integer>> result = new ArrayList<>(); 21 if (root == null) { 22 return result; 23 } 24 25 Queue<TreeNode> queue = new LinkedList<>(); 26 queue.offer(root); 27 28 while (!queue.isEmpty()) { 29 30 ArrayList<Integer> level = new ArrayList<>(); 31 int queueSize = queue.size(); 32 33 for (int i = 0; i < queueSize; i++) { 34 35 TreeNode head = queue.poll(); 36 level.add(head.val); 37 38 if (head.left != null) { 39 queue.offer(head.left); 40 } 41 if (head.right != null) { 42 queue.offer(head.right); 43 } 44 } 45 result.add(level); 46 } 47 48 //reverse the list; 49 Collections.reverse(result); 50 return result; 51 } 52 }
66. Binary Tree Preorder Traversal (思路: 前序、中序、后序三种遍历的递归方式是特别简单的,但是需要掌握非递归遍历的方法,前序的思路很简单,建立一个栈用来保存节点就行,注意往栈里面先加入右子树,再加入左子树)
1 public class Solution { 2 /** 3 * @param root: The root of binary tree. 4 * @return: Preorder in ArrayList which contains node values. 5 */ 6 public ArrayList<Integer> preorderTraversal(TreeNode root) { 7 //because stack is last in first out, root.right should be pushed first 8 //the thought is the same as the level traversal; 9 ArrayList<Integer> result = new ArrayList<>(); 10 if (root == null) { 11 return result; 12 } 13 14 Stack<TreeNode> stack = new Stack<>(); 15 stack.push(root); 16 17 while (!stack.isEmpty()) { 18 19 TreeNode head = stack.pop(); 20 result.add(head.val); 21 22 if (head.right != null) { 23 stack.push(head.right); 24 } 25 if (head.left != null) { 26 stack.push(head.left); 27 } 28 } 29 return result; 30 } 31 /** 32 * the method of recursion 33 * 递归函数可以理解为将节点的值加入链表中 34 public ArrayList<Integer> preorderTraversal(TreeNode root) { 35 ArrayList<Integer> result = new ArrayList<>(); 36 if (root == null) { 37 return result; 38 } 39 helper(result, root); 40 return result; 41 } 42 public void helper(ArrayList<Integer> result, TreeNode root) { 43 if (root == null) { 44 return; 45 } 46 result.add(root.val); 47 helper(result, root.left); 48 helper(result, root.right); 49 } 50 */ 51 }
67. Binary Tree Inorder Traversal (思路:中序遍历跟前序遍历的思路不同,不过还是需要建立一个栈保存节点,由于是先遍历左子树,所以要先遍历到左边的叶节点,然后根据先入后出的特点,退回父节点再进行遍历)
1 public class Solution { 2 /** 3 * @param root: The root of binary tree. 4 * @return: Inorder in ArrayList which contains node values. 5 */ 6 /** 7 public ArrayList<Integer> inorderTraversal(TreeNode root) { 8 ArrayList<Integer> result = new ArrayList<>(); 9 if (root == null) { 10 return result; 11 } 12 helper(result, root); 13 return result; 14 } 15 public void helper(ArrayList<Integer> result, TreeNode root) { 16 if (root == null) { 17 return; 18 } 19 helper(result, root.left); 20 result.add(root.val); 21 helper(result, root.right); 22 } 23 */ 24 public ArrayList<Integer> inorderTraversal(TreeNode root) { 25 //an example will make this problem easy. 26 ArrayList<Integer> result = new ArrayList<>(); 27 if (root == null) { 28 return result; 29 } 30 31 Stack<TreeNode> stack = new Stack<>(); 32 TreeNode cur = root; 33 34 while (cur != null || !stack.isEmpty()) { 35 //get the left tree first 36 while (cur != null) { 37 stack.push(cur); 38 cur = cur.left; 39 } 40 //get the right tree. 41 cur = stack.pop(); 42 result.add(cur.val); 43 cur = cur.right; 44 } 45 return result; 46 } 47 }
1 public class Solution { 2 /** 3 * @param root: The root of binary tree. 4 * @return: Inorder in ArrayList which contains node values. 5 */ 6 /**public ArrayList<Integer> inorderTraversal(TreeNode root) { 7 ArrayList<Integer> result = new ArrayList<>(); 8 if (root == null) { 9 return result; 10 } 11 recHelper(result, root); 12 return result; 13 } 14 public void recHelper(ArrayList<Integer> result, TreeNode root) { 15 if (root == null) { 16 return; 17 } 18 recHelper(result, root.left); 19 result.add(root.val); 20 recHelper(result, root.right); 21 }*/ 22 public ArrayList<Integer> inorderTraversal(TreeNode root) { 23 //三种遍历都需要一个栈来保存节点,需要注意的是中序遍历不同,因为第一个值为左子树的左叶节点,因此需要先遍历到此处,之后再遍历右子树,注意while循环的条件 24 ArrayList<Integer> result = new ArrayList<>(); 25 if (root == null) { 26 return result; 27 } 28 Stack<TreeNode> stack = new Stack<>(); 29 TreeNode cur = root; 30 //cur != null 保证可以进入循环 31 while (cur != null || !stack.isEmpty()) { 32 //遍历到最左边的叶节点(集合中第一个值) 33 while (cur != null) { 34 stack.push(cur); 35 cur = cur.left; 36 } 37 //两次pop之后回到父节点 38 cur = stack.pop(); 39 result.add(cur.val); 40 cur = cur.right; 41 } 42 return result; 43 } 44 }
68. Binary Tree Postorder Traversal (思路:后序遍历跟前序遍历类似,因为他们是对称的,因此跟前序遍历类似,不过需要倒着添加值,因此需要 LinkedList 的 addFirst 功能)
1 public class Solution { 2 /** 3 * @param root: The root of binary tree. 4 * @return: Postorder in ArrayList which contains node values. 5 */ 6 /** 7 * the method of recursion 8 * the thought is the same as inorder and preorder 9 public ArrayList<Integer> postorderTraversal(TreeNode root) { 10 ArrayList<Integer> result = new ArrayList<>(); 11 if (root == null) { 12 return result; 13 } 14 helper(result, root); 15 return result; 16 } 17 private void helper(ArrayList<Integer> result, TreeNode root) { 18 if (root == null) { 19 return; 20 } 21 helper(result, root.left); 22 helper(result, root.right); 23 result.add(root.val); 24 } 25 */ 26 public ArrayList<Integer> postorderTraversal(TreeNode root) { 27 ArrayList<Integer> result = new ArrayList<>(); 28 if (root == null) { 29 return result; 30 } 31 //only linkedList has "addFirst", the thought is the same as preorder 32 //because preorder and postorder is symmetrical(对称的) 33 34 LinkedList<Integer> linkedList = new LinkedList<>(); 35 Stack<TreeNode> stack = new Stack<>(); 36 stack.push(root); 37 38 while (!stack.isEmpty()) { 39 TreeNode cur = stack.pop(); 40 linkedList.addFirst(cur.val); 41 if (cur.left != null) { 42 stack.push(cur.left); 43 } 44 if (cur.right != null) { 45 stack.push(cur.right); 46 } 47 } 48 49 for (int i = 0; i < linkedList.size(); i++) { 50 result.add(linkedList.get(i)); 51 } 52 53 return result; 54 } 55 }
378. Convert Binary Search Tree to Doubly Linked List (思路:递归,分别将左右子树转化为两个 doublyList , 注意建立一个新类DoublyList,有两个参数,头和尾)
/** * Definition for Doubly-ListNode. * public class DoublyListNode { * int val; * DoublyListNode next, prev; * DoublyListNode(int val) { * this.val = val; * this.next = this.prev = null; * } * } */ public class Solution { /** * @param root: The root of tree * @return: the head of doubly list node */ class DoublyList { //build a new class "DoublyList", it has first (head) and last (tail) DoublyListNode first; DoublyListNode last; public DoublyList(DoublyListNode first, DoublyListNode last) { this.first = first; this.last = last; } } public DoublyListNode bstToDoublyList(TreeNode root) { if (root == null) { return null; } DoublyListNode result = recHelper(root).first; return result; } public DoublyList recHelper(TreeNode root) { if (root == null) { return null; } //convert the left tree to a doublyList DoublyList left = recHelper(root.left); //convert the right tree to a doublyList DoublyList right = recHelper(root.right); DoublyList result = new DoublyList(null, null); DoublyListNode node = new DoublyListNode(root.val); //if left tree is null, then the current node is the head of DoublyList //else, the head of the left DoublyList is the head of result //the right is the same. if (left == null) { result.first = node; } else { result.first = left.first; left.last.next = node; node.prev = left.last; } if (right == null) { result.last = node; } else { result.last = right.last; node.next = right.first; right.first.prev = node; } return result; } }
1 /** 2 * Definition for Doubly-ListNode. 3 * public class DoublyListNode { 4 * int val; 5 * DoublyListNode next, prev; 6 * DoublyListNode(int val) { 7 * this.val = val; 8 * this.next = this.prev = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /** 14 * @param root: The root of tree 15 * @return: the head of doubly list node 16 */ 17 //需定义一个新类来存放双链表的头和尾(即一个双链表) 18 class DoublyList { 19 DoublyListNode head; 20 DoublyListNode tail; 21 public DoublyList(DoublyListNode head, DoublyListNode tail) { 22 this.head = head; 23 this.tail = tail; 24 } 25 } 26 public DoublyListNode bstToDoublyList(TreeNode root) { 27 DoublyListNode result = null; 28 if (root == null) { 29 return result; 30 } 31 result = recHelper(root).head; 32 return result; 33 } 34 public DoublyList recHelper(TreeNode root) { 35 if (root == null) { 36 return null; 37 } 38 DoublyList result = new DoublyList(null, null); 39 //这一句写成DoublyList result = null 是错的,注意null的使用 40 //假设已经将左子树和右子树分别转化为一个双链表,然后便将根节点连接起来(这是理解这个递归函数的思路) 41 DoublyList leftList = recHelper(root.left); 42 DoublyList rightList = recHelper(root.right); 43 DoublyListNode cur = new DoublyListNode(root.val); 44 if (leftList == null) { 45 result.head = cur; 46 } else { 47 result.head = leftList.head; 48 leftList.tail.next = cur; 49 cur.prev = leftList.tail; 50 } 51 if (rightList == null) { 52 result.tail = cur; 53 } else { 54 result.tail = rightList.tail; 55 cur.next = rightList.head; 56 rightList.head.prev = cur; 57 } 58 return result; 59 } 60 }
374. Spiral Matrix (思路:注意循环的条件,还有就是注意每一步进行的条件)
1 public class Solution { 2 /** 3 * @param matrix a matrix of m x n elements 4 * @return an integer list 5 */ 6 public List<Integer> spiralOrder(int[][] matrix) { 7 List<Integer> result = new ArrayList<>(); 8 if (matrix == null || matrix.length == 0) { 9 return result; 10 } 11 int row = matrix.length; 12 int column = matrix[0].length; 13 int start = 0; 14 //start is the coordinates of the origin(左上角的坐标,(0,0)(1,1)等等) 15 while (row > start * 2 && column > start * 2) { 16 //an example can explain the judge condition 17 //notice: the bound of cycle in the next code 18 int endX = column - 1 - start; 19 int endY = row - 1 - start; 20 for (int i = start; i <= endX; i++) { 21 result.add(matrix[start][i]); 22 } 23 if (endY > start) { 24 for (int i = start + 1; i <= endY; i++) { 25 result.add(matrix[i][endX]); 26 } 27 } 28 if (endY > start && endX > start) { 29 for (int i = endX - 1; i >= start; i--) { 30 result.add(matrix[endY][i]); 31 } 32 } 33 if (endX > start && endY > start + 1) { 34 for (int i = endY - 1; i > start; i--) { 35 result.add(matrix[i][start]); 36 } 37 } 38 start++; 39 } 40 return result; 41 } 42 }
1 public class Solution { 2 /** 3 * @param matrix a matrix of m x n elements 4 * @return an integer list 5 */ 6 public List<Integer> spiralOrder(int[][] matrix) { 7 //确定整个循环运行的条件,以及每一步运行的条件,最好是画图 8 List<Integer> result = new ArrayList<>(); 9 if (matrix == null || matrix.length == 0) { 10 return result; 11 } 12 if (matrix[0] == null || matrix[0].length == 0) { 13 return result; 14 } 15 int row = matrix.length; 16 int column = matrix[0].length; 17 int start = 0; 18 while (row > start * 2 && column > start * 2) { 19 //定义终止行号和终止列号,start为起始的行号与列号 20 int endX = column - 1 - start; 21 int endY = row - 1 - start; 22 for (int i = start; i <= endX; i++) { 23 result.add(matrix[start][i]); 24 } 25 if (endY > start) { 26 for (int i = start + 1; i <= endY; i++) { 27 result.add(matrix[i][endX]); 28 } 29 } 30 if (endX > start && endY > start) { 31 for (int i = endX - 1; i >= start; i--) { 32 result.add(matrix[endY][i]); 33 } 34 } 35 if (endY - start >= 2 && endX > start) { 36 for (int i = endY - 1; i > start; i--) { 37 result.add(matrix[i][start]); 38 } 39 } 40 start++; 41 } 42 return result; 43 } 44 }
105. Copy List with Random Pointer (思路: 分三步,第一,复制所有节点到当前节点之后;第二,复制所有的随机指针;第三, 将链表分成两个链表)
1 /** 2 * Definition for singly-linked list with a random pointer. 3 * class RandomListNode { 4 * int label; 5 * RandomListNode next, random; 6 * RandomListNode(int x) { this.label = x; } 7 * }; 8 */ 9 public class Solution { 10 /** 11 * @param head: The head of linked list with a random pointer. 12 * @return: A new head of a deep copy of the list. 13 */ 14 public RandomListNode copyRandomList(RandomListNode head) { 15 //Three steps: 16 if (head == null) { 17 return null; 18 } 19 copyNodes(head); 20 copyRandom(head); 21 return splitList(head); 22 } 23 public void copyNodes(RandomListNode head) { 24 //Step 1 : copy all nodes 25 RandomListNode cur = head; 26 while (cur != null) { 27 RandomListNode copy = new RandomListNode(cur.label); 28 copy.next = cur.next; 29 copy.random = null; 30 //connect node and cloned node 31 cur.next = copy; 32 //copy next node 33 cur = copy.next; 34 } 35 } 36 public void copyRandom(RandomListNode head) { 37 //Step 2 : copy the random pointer 38 RandomListNode cur = head; 39 while (cur != null) { 40 RandomListNode copy = cur.next; 41 if (cur.random != null) { 42 copy.random = cur.random; 43 } 44 //copy random pointer of next node 45 cur = copy.next; 46 } 47 } 48 public RandomListNode splitList(RandomListNode head) { 49 //Step 3 : split it to two lists 50 RandomListNode cur = head; 51 RandomListNode copyCur = cur.next; 52 RandomListNode copyHead = cur.next; 53 //save new head of cloned list 54 cur = copyCur.next; 55 while (cur != null) { 56 copyCur.next = cur.next; 57 copyCur = copyCur.next; 58 cur.next = copyCur.next; 59 cur = cur.next; 60 } 61 return copyHead; 62 } 63 }
1 /** 2 * Definition for singly-linked list with a random pointer. 3 * class RandomListNode { 4 * int label; 5 * RandomListNode next, random; 6 * RandomListNode(int x) { this.label = x; } 7 * }; 8 */ 9 public class Solution { 10 /** 11 * @param head: The head of linked list with a random pointer. 12 * @return: A new head of a deep copy of the list. 13 */ 14 //分为有顺序的三步:第一步复制所有节点,第二步复制随机指针,第三步将两个链表分开 15 //需要注意的是:复制随机指针的时候需要判断是否为空;分开链表的时候,需要先将当前节点遍历到head的下一跳,防止head.next.next出现空指针 16 public RandomListNode copyRandomList(RandomListNode head) { 17 copyNodes(head); 18 copyRandom(head); 19 return splitList(head); 20 } 21 public void copyNodes(RandomListNode head) { 22 if (head == null) { 23 return; 24 } 25 while (head != null) { 26 RandomListNode copy = new RandomListNode(head.label); 27 RandomListNode temp = head.next; 28 head.next = copy; 29 copy.next = temp; 30 head = copy.next; 31 } 32 } 33 public void copyRandom(RandomListNode head) { 34 if (head == null) { 35 return; 36 } 37 while (head != null) { 38 if (head.random != null) { 39 head.next.random = head.random.next; 40 } 41 head = head.next.next; 42 } 43 } 44 public RandomListNode splitList(RandomListNode head) { 45 if (head == null) { 46 return null; 47 } 48 RandomListNode copyHead = head.next; 49 RandomListNode copyCur = copyHead; 50 head.next = copyCur.next; 51 head = head.next; 52 while (head != null) { 53 copyCur.next = head.next; 54 copyCur = copyCur.next; 55 head.next = copyCur.next; 56 head = head.next; 57 } 58 return copyHead; 59 } 60 }
12. Min Stack (思路:建一个辅助栈保存当前的最小值,每次进行pop()操作时,需要把最小栈的peek也pop掉)
1 public class MinStack { 2 Stack<Integer> stack; 3 Stack<Integer> minStack; 4 public MinStack() { 5 //an additional stack is needed to save current min 6 stack = new Stack<>(); 7 minStack = new Stack<>(); 8 } 9 public void push(int number) { 10 stack.push(number); 11 if (minStack.isEmpty()) { 12 minStack.push(number); 13 } else { 14 minStack.push(Math.min(number, minStack.peek())); 15 } 16 } 17 public int pop() { 18 minStack.pop(); 19 return stack.pop(); 20 } 21 public int min() { 22 return minStack.peek(); 23 } 24 }
381. Spiral Matrix II(思路: 按照Spiral Matrix打印的方式分成四步,同样第一步肯定是要进行的,后面的三步需要判断(举个例子就容易懂了),不过对于正方形的矩阵后面三步的判断条件是一样的,可以同时进行)
1 public class Solution { 2 /** 3 * @param n an integer 4 * @return a square matrix 5 */ 6 public int[][] generateMatrix(int n) { 7 if (n <= 0) { 8 return new int[0][0]; 9 } 10 int start = 0; 11 int num = 1; 12 int[][] result = new int[n][n]; 13 while (n > 0) { 14 for (int i = start; i < n; i++) { 15 result[start][i] = num++; 16 } 17 if (n - start >= 2) { //the code of this line is important, it can 18 //it can decide if we will start step 2 to step 4 19 //it is easy to understand if you have an instance 20 for (int i = start + 1; i < n; i++) { 21 result[i][n - 1] = num++; 22 } 23 for (int i = n - 2; i >= start; i--) { 24 result[n - 1][i] = num++; 25 } 26 for (int i = n - 2; i > start; i--) { 27 result[i][start] = num++; 28 } 29 } 30 n = n - 1; 31 start++; 32 } 33 return result; 34 } 35 }
5. Optimize Time and Space
46. Majority Number (思路:用count记录次数,用number记录当前的数字,对数组进行遍历,如果跟number相同,count就加1.如果不同count减1,由于要找的数字次数大于一半,也就大于其他所有数字的次数之和,那么最后保存的数字必然就是我们所要的)
1 public class Solution { 2 /** 3 * @param nums: a list of integers 4 * @return: find a majority number 5 */ 6 public int majorityNumber(ArrayList<Integer> nums) { 7 //整体思路:用count记录次数,用number记录当前的数字,对数组进行遍历, 8 //如果跟number相同,count就加1,如果不同count减1,由于要找的数字次数 9 //大于一半,也就大于其他所有数字的次数之和, 10 //那么最后保存的数字必然就是我们所要的。 11 if (nums == null || nums.size() == 0) { 12 return 0; 13 } 14 int num = 0; 15 int count = 0; 16 for (int i = 0; i < nums.size(); i++) { 17 if (count == 0) { 18 num = nums.get(i); 19 } 20 if (num == nums.get(i)) { 21 count++; 22 } else { 23 count--; 24 } 25 } 26 return num; 27 } 28 }
1 public class Solution { 2 /** 3 * @param nums: a list of integers 4 * @return: find a majority number 5 */ 6 public int majorityNumber(ArrayList<Integer> nums) { 7 //整体思路:用count记录次数,用number记录当前的数字,对数组进行遍历, 8 //如果跟number相同,count就加1,如果不同count减1,由于要找的数字次数 9 //大于一半,也就大于其他所有数字的次数之和, 10 //那么最后保存的数字必然就是我们所要的。 11 if (nums == null || nums.size() == 0) { 12 return 0; 13 } 14 /** 15 * int count = 1; 16 int number = nums.get(0); 17 for (int i = 1; i < nums.size(); i++) { 18 if (nums.get(i) == number) { 19 count++; 20 } else { 21 count--; 22 } 23 if (count == 0) { 24 number = nums.get(i); 25 count++; 26 } 27 } 28 */ 29 int count = 0; 30 int number = 0; 31 for (int i = 0; i < nums.size(); i++) { 32 if (count == 0) { 33 number = nums.get(i); 34 //count++; 35 } 36 if (number == nums.get(i)) { 37 count++; 38 } else { 39 count--; 40 } 41 } 42 return number; 43 } 44 }
1 public class Solution { 2 /** 3 * @param nums: a list of integers 4 * @return: find a majority number 5 */ 6 public int majorityNumber(ArrayList<Integer> nums) { 7 //整体思路:用count记录次数,用number记录当前的数字,对数组进行遍历, 8 //如果跟number相同,count就加1,如果不同count减1,由于要找的数字次数 9 //大于一半,也就大于其他所有数字的次数之和, 10 //那么最后保存的数字必然就是我们所要的。 11 /**if (nums == null || nums.size() == 0) { 12 return -1; 13 } 14 int number = nums.get(0); 15 int count = 1; 16 for (int i = 1; i < nums.size(); i++) { 17 if (nums.get(i) == number) { 18 count++; 19 } else { 20 count--; 21 if (count < 0) { 22 count = 1; 23 number = nums.get(i); 24 } 25 } 26 } 27 return number; 28 }*/ 29 if (nums == null || nums.size() == 0) { 30 return -1; 31 } 32 int number = 0; 33 int count = 0; 34 for (int i = 0; i < nums.size(); i++) { 35 if (count == 0) { 36 number = nums.get(i); 37 } 38 if (number == nums.get(i)) { 39 count++; 40 } else { 41 count--; 42 } 43 } 44 return number; 45 } 46 }
47. Majority Number II (思路: 同上,不过需要两个num和count,最后需要选择较大的count对应的num,注意判断条件的顺序)
1 public class Solution { 2 /** 3 * @param nums: A list of integers 4 * @return: The majority number that occurs more than 1/3 5 */ 6 public int majorityNumber(ArrayList<Integer> nums) { 7 if (nums == null || nums.size() == 0) { 8 return 0; 9 } 10 int num1 = 0; 11 int num2 = 0; 12 int count1 = 0; 13 int count2 = 0; 14 for (int i = 0; i < nums.size(); i++) { 15 /** 16 if (count1 == 0) { 17 num1 = nums.get(i); 18 count1++; 19 } else if (count2 == 0) { 20 num2 = nums.get(i); 21 count2++; 22 } else if (nums.get(i) == num1) { 23 count1++; 24 } else if (nums.get(i) == num2) { 25 count2++; 26 } else { 27 count1--; 28 count2--; 29 } 30 */ 31 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 32 //the above code is wrong, test data [1 1 1 1 2 2 3 3 4 4 4] is not accepted 33 //so the order of 'if' is very important 34 if (nums.get(i) == num1) { 35 count1++; 36 } else if (nums.get(i) == num2) { 37 count2++; 38 } else if (count1 == 0) { 39 num1 = nums.get(i); 40 count1++; 41 } else if (count2 == 0) { 42 num2 = nums.get(i); 43 count2++; 44 } else { 45 count1--; 46 count2--; 47 } 48 } 49 count1 = 0; 50 count2 = 0; 51 for (int i = 0; i < nums.size(); i++) { 52 if (nums.get(i) == num1) { 53 count1++; 54 } else if (nums.get(i) == num2) { 55 count2++; 56 } 57 } 58 return count1 > count2 ? num1 : num2; 59 } 60 }
41. Maximum Subarray (思路:定义两个变量,当前累加和和最大累加和,如果当前累加和是负的,那么从下一个数字开始继续累加,同时更新最大累加和)
1 public class Solution { 2 /** 3 * @param nums: A list of integers 4 * @return: A integer indicate the sum of max subarray 5 */ 6 public int maxSubArray(int[] nums) { 7 if (nums == null || nums.length == 0) { 8 return 0; 9 } 10 int maxSum = nums[0]; 11 int curSum = 0; 12 for (int i = 0; i < nums.length; i++) { 13 //if the current sum < 0, then get the sum from next number 14 if (curSum < 0) { 15 curSum = nums[i]; 16 } else { 17 curSum += nums[i]; 18 } 19 if (curSum > maxSum) { 20 maxSum = curSum; 21 } 22 } 23 return maxSum; 24 } 25 }
379.Reorder array to construct the minimum number(重新定义一种排序规则)
1 public class Solution { 2 /** 3 * @param nums n non-negative integer array 4 * @return a string 5 */ 6 public String minNumber(int[] nums) { 7 //边界判断 8 if (nums == null || nums.length == 0) { 9 return ""; 10 } 11 //将整数数组转成字符串数组并从小到大排序(按自定义的排序规则) 12 int numsLen = nums.length; 13 String[] str = new String[numsLen]; 14 for (int i = 0; i < numsLen; i++) { 15 str[i] = nums[i]+ ""; 16 } 17 Arrays.sort(str, new CompareString()); 18 //将排序好的字符串数组连接起来 19 String result = ""; 20 for (int i = 0; i < numsLen; i++) { 21 result = result.concat(str[i]); 22 } 23 //因为返回的是整数,需要将前面为0的舍去 24 int i = 0; 25 while (i < numsLen && result.charAt(i) == '0') { 26 i++; 27 } 28 if (i == numsLen) { 29 return "0"; 30 } 31 return result;//.substring(i); 32 } 33 //重新定义一个类来实现Comparator接口,按照升序排序 34 class CompareString implements Comparator<String> { 35 public int compare(String a, String b) { 36 String ab = a.concat(b); 37 String ba = b.concat(a); 38 return ab.compareTo(ba); 39 } 40 } 41 }
第二种更严谨
1 public class Solution { 2 /** 3 * @param nums n non-negative integer array 4 * @return a string 5 */ 6 public String minNumber(int[] nums) { 7 if (nums == null || nums.length == 0) { 8 return null; 9 } 10 String[] str = new String[nums.length]; 11 for (int i = 0; i < nums.length; i++) { 12 str[i] = nums[i] + ""; 13 } 14 Arrays.sort(str, new CompareString()); 15 String result = ""; 16 for (int i = 0; i < nums.length; i++) { 17 result = result.concat(str[i]); 18 } 19 int i = 0; 20 while (i < result.length() && result.charAt(i) == '0') { 21 i++; 22 } 23 if (i == result.length()) { 24 return "0"; 25 } 26 return result.substring(i); 27 } 28 class CompareString implements Comparator<String> { 29 public int compare(String a, String b) { 30 String ab = a.concat(b); 31 String ba = b.concat(a); 32 return ab.compareTo(ba); 33 } 34 } 35 }
1 public class Solution { 2 /** 3 * @param nums n non-negative integer array 4 * @return a string 5 */ 6 /**public String minNumber(int[] nums) { 7 String result = ""; 8 if (nums == null || nums.length == 0) { 9 return result; 10 } 11 //为防止数字溢出的情况,需要先将数字变为字符串 12 String[] str = new String[nums.length]; 13 for (int i = 0; i < nums.length; i++) { 14 str[i] = nums[i] + ""; 15 } 16 //按照指定排序规则进行排序 17 Arrays.sort(str, new CompareString()); 18 for (int i = 0; i < str.length; i++) { 19 result += str[i]; 20 } 21 //将前面为0的去掉 22 int i = 0; 23 while (i < result.length() && result.charAt(i) == '0') { 24 i++; 25 } 26 if (i == result.length()) { 27 return "0"; 28 } 29 return result.substring(i); 30 } 31 class CompareString implements Comparator<String> { 32 public int compare(String a, String b) { 33 String ab = a.concat(b); 34 String ba = b.concat(a); 35 return ab.compareTo(ba); 36 } 37 }*/ 38 //匿名内部类 39 public String minNumber(int[] nums) { 40 String result = ""; 41 if (nums == null || nums.length == 0) { 42 return result; 43 } 44 String[] str = new String[nums.length]; 45 for (int i = 0; i < nums.length; i++) { 46 str[i] = nums[i] + ""; 47 } 48 Arrays.sort(str, new Comparator<String>() { 49 public int compare(String a, String b) { 50 String ab = a.concat(b); 51 String ba = b.concat(a); 52 return ab.compareTo(ba); 53 } 54 }); 55 for (int i = 0; i < str.length; i++) { 56 result += str[i]; 57 } 58 int i = 0; 59 while (i < result.length() && result.charAt(i) == '0') { 60 i++; 61 } 62 if (i == result.length()) { 63 return "0"; 64 } 65 return result.substring(i); 66 } 67 }
532. Reverse Pairs
1 public class Solution { 2 /** 3 * @param A an array 4 * @return total of reverse pairs 5 */ 6 long count = 0; 7 public long reversePairs(int[] a) { 8 if (a == null || a.length == 0) { 9 return 0; 10 } 11 int[] temp = new int[a.length]; 12 divide(a, 0, a.length - 1, temp); 13 return count; 14 } 15 public void divide(int[] a, int start, int end, int[] temp) { 16 if (start >= end) { 17 return; 18 } 19 int mid = start + (end - start) / 2; 20 divide(a, start, mid, temp); 21 divide(a, mid + 1, end, temp); 22 mergeSort(a, start, end, temp); 23 } 24 public void mergeSort(int[] a, int start, int end, int[] temp) { 25 if (start >= end) { 26 return; 27 } 28 int mid = start + (end - start) / 2; 29 int left = start; 30 int right = mid + 1; 31 for (left = start; left <= mid; left++) { 32 while (right <= end && a[left] > a[right]) { 33 right++; 34 } 35 count += right - (mid + 1); 36 } 37 int leftIndex = start; 38 int rightIndex = mid + 1; 39 int tempIndex = start; 40 while (leftIndex <= mid && rightIndex <= end) { 41 if (a[leftIndex] < a[rightIndex]) { 42 temp[tempIndex++] = a[leftIndex++]; 43 } else { 44 temp[tempIndex++] = a[rightIndex++]; 45 } 46 } 47 while (leftIndex <= mid) { 48 temp[tempIndex++] = a[leftIndex++]; 49 } 50 while (rightIndex <= end) { 51 temp[tempIndex++] = a[rightIndex++]; 52 } 53 //复制temp到a的时候注意是start和end 54 for (int i = start; i <= end; i++) { 55 a[i] = temp[i]; 56 } 57 } 58 }
381.Spiral Matrix II
1 public class Solution { 2 /** 3 * @param n an integer 4 * @return a square matrix 5 */ 6 public int[][] generateMatrix(int n) { 7 int[][] result = new int[n][n]; 8 if (n <= 0) { 9 return result; 10 } 11 int start = 0; 12 int number = 1; 13 while (n > 2 * start) { 14 int end = n - start - 1; 15 for (int i = start; i <= end; i++) { 16 result[start][i] = number++; 17 } 18 if (end > start) { 19 for (int i = start + 1; i < end; i++) { 20 result[i][end] = number++; 21 } 22 for (int i = end; i > start; i--) { 23 result[end][i] = number++; 24 } 25 for (int i = end; i > start; i--) { 26 result[i][start] = number++; 27 } 28 } 29 start++; 30 } 31 return result; 32 } 33 }
380. Intersection of Two Linked Lists
1 /** 2 * Definition for singly-linked list. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { 7 * val = x; 8 * next = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /** 14 * @param headA: the first list 15 * @param headB: the second list 16 * @return: a ListNode 17 */ 18 public ListNode getIntersectionNode(ListNode headA, ListNode headB) { 19 //整体思路:首先获得两个链表的长度,然后将长的链表遍历到跟短的一样,然后两个链表同时遍历,找到共同的节点 20 if (headA == null || headB == null) { 21 return null; 22 } 23 int aLen = getListLength(headA); 24 int bLen = getListLength(headB); 25 if (aLen < bLen) { 26 for (int i = aLen; i < bLen; i++) { 27 headB = headB.next; 28 } 29 } else { 30 for (int i = bLen; i < aLen; i++) { 31 headA = headA.next; 32 } 33 } 34 ListNode common = null; 35 while (headA != null) { 36 if (headA == headB) { 37 common = headA; 38 return common; 39 } 40 headA = headA.next; 41 headB = headB.next; 42 } 43 return common; 44 } 45 public int getListLength(ListNode head) { 46 if (head == null) { 47 return 0; 48 } 49 int len = 0; 50 while (head != null) { 51 head = head.next; 52 len++; 53 } 54 return len; 55 } 56 }
3.Digit Counts(第一种:暴力解法,直接遍历,数每个数字中k的个数)
第二种:
当某一位的数字小于i时,那么该位出现i的次数为:更高位数字x当前位数 当某一位的数字等于i时,那么该位出现i的次数为:更高位数字x当前位数+低位数字+1 当某一位的数字大于i时,那么该位出现i的次数为:(更高位数字+1)x当前位数
假设一个5位数N=abcde,我们现在来考虑百位上出现2的次数,即,从0到abcde的数中, 有多少个数的百位上是2。分析完它,就可以用同样的方法去计算个位,十位,千位, 万位等各个位上出现2的次数。
当百位c为0时,比如说12013,0到12013中哪些数的百位会出现2?我们从小的数起, 200~299, 1200~1299, 2200~2299, … , 11200~11299, 也就是固定低3位为200~299,然后高位依次从0到11,共12个。再往下12200~12299 已经大于12013,因此不再往下。所以,当百位为0时,百位出现2的次数只由更高位决定, 等于更高位数字(12)x当前位数(100)=1200个。
当百位c为1时,比如说12113。分析同上,并且和上面的情况一模一样。 最大也只能到11200~11299,所以百位出现2的次数也是1200个。
上面两步综合起来,可以得到以下结论:
当某一位的数字小于2时,那么该位出现2的次数为:更高位数字x当前位数
当百位c为2时,比如说12213。那么,我们还是有200~299, 1200~1299, 2200~2299, … , 11200~11299这1200个数,他们的百位为2。但同时,还有一部分12200~12213, 共14个(低位数字+1)。所以,当百位数字为2时, 百位出现2的次数既受高位影响也受低位影响,结论如下:
当某一位的数字等于2时,那么该位出现2的次数为:更高位数字x当前位数+低位数字+1
当百位c大于2时,比如说12313,那么固定低3位为200~299,高位依次可以从0到12, 这一次就把12200~12299也包含了,同时也没低位什么事情。因此出现2的次数是: (更高位数字+1)x当前位数。结论如下:
当某一位的数字大于2时,那么该位出现2的次数为:(更高位数字+1)x当前位数
1 class Solution { 2 /* 3 * param k : As description. 4 * param n : As description. 5 * return: An integer denote the count of digit k in 1..n 6 */ 7 // public int digitCounts(int k, int n) { 8 // if (k < 0 || k > 9 || n < 0) { 9 // return 0; 10 // } 11 // int count = 0; 12 // for (int i = k; i <= n; i++) { 13 // count += countK(k, i); 14 // } 15 // return count; 16 // } 17 // public int countK(int k, int num) { 18 // int count = 0; 19 // if (k < 0 || num < 0) { 20 // return 0; 21 // } 22 // if (k == 0 && num == 0) { 23 // return 1; 24 // } 25 // while (num > 0) { 26 // if (num % 10 == k) { 27 // count++; 28 // } 29 // num = num / 10; 30 // } 31 // return count; 32 // } 33 public int digitCounts(int k, int n) { 34 if (k < 0 || k > 9 || n < 0) { 35 return 0; 36 } 37 if (k == 0) { 38 return count0(n); 39 } 40 return countOther(k, n); 41 } 42 public int count0(int num) { 43 if (num < 0) { 44 return 0; 45 } 46 int count = 0; 47 for (int i = 0; i <= num; i++) { 48 count += count0Helper(i); 49 } 50 return count; 51 } 52 public int count0Helper(int num) { 53 if (num < 0) { 54 return 0; 55 } 56 int count = 0; 57 if (num == 0) { 58 return 1; 59 } 60 while (num > 0) { 61 if (num % 10 == 0) { 62 count++; 63 } 64 num = num / 10; 65 } 66 return count; 67 } 68 public int countOther(int k, int num) { 69 int count = 0; 70 int low = 0; 71 int high = 0; 72 int cur = 0; 73 int factor = 1; 74 while (num / factor > 0) { 75 low = num - (num / factor) * factor; 76 high = num / (factor * 10); 77 cur = (num / factor) % 10; 78 if (cur < k) { 79 count += high * factor; 80 } else if (cur == k) { 81 count += high * factor + low + 1; 82 } else { 83 count += (high + 1) * factor; 84 } 85 factor = factor * 10; 86 } 87 return count; 88 } 89 }
5.Kth Largest Element(思路:从大到小快速排序的过程中找第K大的元素)
1 class Solution { 2 /* 3 * @param k : description of k 4 * @param nums : array of nums 5 * @return: description of return 6 */ 7 public int kthLargestElement(int k, int[] nums) { 8 //思路:进行从大到小快速排序的时候计算找第K大的元素 9 if (nums == null || nums.length == 0 || k < 1) { 10 return 0; 11 } 12 return quickSelect(nums, 0, nums.length - 1, k); 13 } 14 public int quickSelect(int[] nums, int start, int end, int k) { 15 if (start > end) { 16 return 0; 17 } 18 int left = start; 19 int right = end; 20 int mid = start + (end - start) / 2; 21 int pivot = nums[mid]; 22 while (left <= right) { 23 //必须是<= 因为必须出现后面所需要的两种排序后情况 24 while (left <= right && nums[left] > pivot) { 25 left++; 26 } 27 while (left <= right && nums[right] < pivot) { 28 right--; 29 } 30 if (left <= right) { 31 int temp = nums[left]; 32 nums[left] = nums[right]; 33 nums[right] = temp; 34 left++; 35 right--; 36 } 37 } 38 //快速排序后只有两种情况:start-right-pivot-left-end 和 start-right-left-end,然后判断分别判断k在前面和后面的情况(举例说明) 39 if (k <= right - start + 1) { 40 return quickSelect(nums, start, right, k); 41 } else if (k > left - start) { 42 return quickSelect(nums, left, end, k - (left - start)); 43 } else { 44 return nums[right + 1]; 45 } 46 } 47 }
4.Ugly Number II(丑数必然是前面的丑数乘以2,3,5的结果,那么下一个丑数必然是之前的丑数)
1 class Solution { 2 /** 3 * @param n an integer 4 * @return the nth prime number as description. 5 */ 6 public int nthUglyNumber(int n) { 7 //思路:丑数必然是前面的丑数乘以2,3,5的结果,那么下一个丑数必然是之前的丑数 8 //乘以2,3,5中的最小数 9 if (n <= 0) { 10 return 0; 11 } 12 ArrayList<Integer> result = new ArrayList<>(); 13 result.add(1); 14 int p2 = 0; 15 int p3 = 0; 16 int p5 = 0; 17 for (int i = 1; i <= n; i++) { 18 int lastUglyNum = result.get(i - 1); 19 //找到第一个分别乘以2,3,5之后大于当前丑数的位置 20 while (result.get(p2) * 2 <= lastUglyNum) { 21 p2++; 22 } 23 while (result.get(p3) * 3 <= lastUglyNum) { 24 p3++; 25 } 26 while (result.get(p5) * 5 <= lastUglyNum) { 27 p5++; 28 } 29 result.add(Math.min(result.get(p2) * 2, Math.min(result.get(p3) * 3, result.get(p5) * 5))); 30 } 31 return result.get(n - 1); 32 } 33 }
6. Skills in Interview
97. Maximum Depth of Binary Tree(左子树和右子树中较大的深度加上根节点的深度)
1 /** 2 * Definition of TreeNode: 3 * public class TreeNode { 4 * public int val; 5 * public TreeNode left, right; 6 * public TreeNode(int val) { 7 * this.val = val; 8 * this.left = this.right = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /** 14 * @param root: The root of binary tree. 15 * @return: An integer. 16 */ 17 public int maxDepth(TreeNode root) { 18 if (root == null) { 19 return 0; 20 } 21 //加的1为根节点 22 //简单理解为:左子树和右子树中较大的深度加上根节点的深度 23 return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1; 24 } 25 }
82.Single Number(由于异或是不同为1,相同为0,那么数组中所有的数字依次异或)
1 public class Solution { 2 /** 3 *@param A : an integer array 4 *return : a integer 5 */ 6 public int singleNumber(int[] a) { 7 //由于异或是不同为1,相同为0,那么数组中所有的数字依次异或,相同的异或为 8 //0,0与目标数字异或还未目标数字,任何数字与0异或不变. 9 if (a == null || a.length == 0) { 10 return 0; 11 } 12 int num = a[0]; 13 for (int i = 1; i < a.length; i++) { 14 num = num ^ a[i]; 15 } 16 return num; 17 } 18 }
56.Two Sum(思路: 由于map存入相同的元素会覆盖,因此需要新建一个类来保存索引和值)
1 class Node { 2 int val; 3 int key; 4 public Node(int key, int val) { 5 this.key = key; 6 this.val = val; 7 } 8 } 9 public class Solution { 10 /* 11 * @param numbers : An array of Integer 12 * @param target : target = numbers[index1] + numbers[index2] 13 * @return : [index1 + 1, index2 + 1] (index1 < index2) 14 */ 15 public int[] twoSum(int[] numbers, int target) { 16 if (numbers == null || numbers.length == 0) { 17 return new int[2]; 18 } 19 ArrayList<Node> nodes = new ArrayList<>(); 20 for (int i = 0; i < numbers.length; i++) { 21 nodes.add(new Node(i, numbers[i])); 22 } 23 Collections.sort(nodes, new Comparator<Node>() { 24 public int compare(Node a, Node b) { 25 return a.val - b.val; 26 } 27 }); 28 int left = 0; 29 int right = numbers.length - 1; 30 int[] result = new int[2]; 31 while (left < right) { 32 if (nodes.get(left).val + nodes.get(right).val == target) { 33 if (nodes.get(left).key < nodes.get(right).key) { 34 result[0] = nodes.get(left).key; 35 result[1] = nodes.get(right).key; 36 return result; 37 } else { 38 result[0] = nodes.get(right).key; 39 result[1] = nodes.get(left).key; 40 return result; 41 } 42 } else if (nodes.get(left).val + nodes.get(right).val < target) { 43 left++; 44 } else { 45 right--; 46 } 47 } 48 return new int[2]; 49 } 50 }
1 public class Solution { 2 /* 3 * @param numbers : An array of Integer 4 * @param target : target = numbers[index1] + numbers[index2] 5 * @return : [index1 + 1, index2 + 1] (index1 < index2) 6 */ 7 public int[] twoSum(int[] numbers, int target) { 8 if (numbers == null || numbers.length < 2) { 9 return new int[2]; 10 } 11 //将所有数字和它的索引加入加入集合中 12 ArrayList<Node> nodes = new ArrayList<>(); 13 for (int i = 0; i < numbers.length; i++) { 14 nodes.add(new Node(i, numbers[i])); 15 } 16 //根据值从小到大对集合进行排序 17 Collections.sort(nodes, new Comparator<Node>(){ 18 public int compare(Node a, Node b) { 19 return a.val - b.val; 20 } 21 }); 22 //利用双指针进行寻找 23 int[] result = new int[2]; 24 int left = 0; 25 int right = nodes.size() - 1; 26 while (left < right) { 27 if (nodes.get(left).val + nodes.get(right).val == target) { 28 if (nodes.get(left).key < nodes.get(right).key) { 29 result[0] = nodes.get(left).key; 30 result[1] = nodes.get(right).key; 31 } else { 32 result[1] = nodes.get(left).key; 33 result[0] = nodes.get(right).key; 34 } 35 return result; 36 } else if (nodes.get(left).val + nodes.get(right).val < target) { 37 left++; 38 } else { 39 right--; 40 } 41 } 42 return result; 43 } 44 } 45 //建立一个新的类节点用于保存索引和值,不能用hashmap,因为hashmap只能通过键获得值,如果将值作为键,索引作为值的话,由于可能存在相同的值,hashmap将会被覆盖 46 class Node{ 47 int val; 48 int key; 49 public Node(int key, int val) { 50 this.key = key; 51 this.val = val; 52 } 53 }
53.Reverse Words in a String(用空格将字符串分开,如果中间或者前面或者后面有很多空格的话,那么数组中这个元素就为空)
1 public class Solution { 2 /** 3 * @param s : A string 4 * @return : A string 5 */ 6 public String reverseWords(String s) { 7 // null 表示没有传string对象, s.length() == 0 表示传了,但是什么也没有、 8 // return "" 表示返回一个空的字符串 return " "表示传了一个空格 9 if (s == null || s.length() == 0) { 10 return ""; 11 } 12 //用空格将字符串分开,如果中间或者前面或者后面有很多空格的话,那么数组中这个元素就为空 13 //利用stringbuffer的append方法 14 String[] wordArr = s.split(" "); 15 StringBuffer sb = new StringBuffer(); 16 for (int i = wordArr.length - 1; i >= 0; i--) { 17 if (wordArr[i] != " ") { 18 sb.append(wordArr[i]).append(" "); 19 } 20 } 21 return sb.length() == 0 ? "" : sb.substring(0, sb.length() - 1); 22 } 23 }
1 public class Solution { 2 /** 3 * @param s : A string 4 * @return : A string 5 */ 6 public String reverseWords(String s) { 7 //不用去管前导空格、尾随空格、中间空格,只需要将字符串用空格分开,然后只对字符串数组中的非空格字符串进行处理,每个后面加个空格 8 if (s == null || s.length() == 0) { 9 return ""; 10 } 11 int count = 0; 12 String[] str = s.split(" "); 13 StringBuffer sb = new StringBuffer(); 14 for (int i = str.length - 1; i >= 0; i--) { 15 if (str[i] != " ") { 16 sb.append(str[i]).append(" "); 17 count++; 18 } 19 } 20 return count == 0 ? "" : sb.substring(0, sb.length() - 1); 21 } 22 }
8.Rotate String (思路:举个简单的例子,从后面反转n个,相当于len-n、n分别反转之后再整体反转)
1 public class Solution { 2 /** 3 * @param str: an array of char 4 * @param offset: an integer 5 * @return: nothing 6 */ 7 public void rotateString(char[] str, int offset) { 8 if (str == null || str.length == 0) { 9 return; 10 } 11 int len = str.length; 12 int off = offset % len; 13 int firstEnd = len - off - 1; 14 int secondStart = firstEnd + 1; 15 reverse(str, 0, firstEnd); 16 reverse(str, secondStart, str.length - 1); 17 reverse(str, 0, str.length - 1); 18 } 19 //举个简单的例子,从后面反转n个,相当于len-n、n分别反转之后再整体反转 20 public void reverse(char[] str, int start, int end) { 21 if (str == null || str.length == 0) { 22 return; 23 } 24 while (start < end) { 25 char temp = str[start]; 26 str[start] = str[end]; 27 str[end] = temp; 28 start++; 29 end--; 30 } 31 } 32 }
1 public class Solution { 2 /** 3 * @param str: an array of char 4 * @param offset: an integer 5 * @return: nothing 6 */ 7 public void rotateString(char[] str, int offset) { 8 if (str == null || str.length == 0) { 9 return; 10 } 11 offset = offset % str.length; 12 int len = str.length - 1; 13 reverse(str, 0, len - offset); 14 reverse(str, len - offset + 1, len); 15 reverse(str, 0, len); 16 } 17 //举个简单的例子,从后面反转n个,相当于(0, len - n) (len - n + 1, n)分别反转之后再整体反转 18 public void reverse(char[] str, int start, int end) { 19 int left = start; 20 int right = end; 21 while (left < right) { 22 char temp = str[left]; 23 str[left] = str[right]; 24 str[right] = temp; 25 left++; 26 right--; 27 } 28 } 29 }
1. A + B Problem (思路:所以:a + b = (a ^ b) + (a & b << 1))
1 class Solution { 2 /* 3 * param a: The first integer 4 * param b: The second integer 5 * return: The sum of a and b 6 */ 7 public int aplusb(int a, int b) { 8 // 主要利用异或运算来完成 9 // 异或运算有一个别名叫做:不进位加法 10 // 那么a ^ b就是a和b相加之后,该进位的地方不进位的结果 11 // 然后下面考虑哪些地方要进位,自然是a和b里都是1的地方 12 // a & b就是a和b里都是1的那些位置,a & b << 1 就是进位 13 // 之后的结果。所以:a + b = (a ^ b) + (a & b << 1) 14 // 令a' = a ^ b, b' = (a & b) << 1 15 // 可以知道,这个过程是在模拟加法的运算过程,进位不可能 16 // 一直持续,所以b最终会变为0。因此重复做上述操作就可以 17 // 求得a + b的值。 18 while (b != 0) { 19 int newA = a ^ b; 20 int newB = (a & b) << 1; 21 a = newA; 22 b = newB; 23 } 24 return a; 25 } 26 };
61.Search for a Range (思路:二分法查找出第一个和最后一个target)
1 public class Solution { 2 /** 3 *@param A : an integer sorted array 4 *@param target : an integer to be inserted 5 *return : a list of length 2, [index1, index2] 6 */ 7 public int[] searchRange(int[] a, int target) { 8 //直接用双指针做 9 int[] result = new int[]{-1, -1}; 10 if (a == null || a.length == 0) { 11 return result; 12 } 13 int left = 0; 14 int right = a.length - 1; 15 while (left <= right) { 16 while (left < a.length - 1 && a[left] != target) { 17 left++; 18 } 19 while (right >= 0 && a[right] != target) { 20 right--; 21 } 22 if (left <= right) { 23 result[0] = left; 24 result[1] = right; 25 return result; 26 } 27 } 28 return result; 29 } 30 }
1 public class Solution { 2 /** 3 *@param A : an integer sorted array 4 *@param target : an integer to be inserted 5 *return : a list of length 2, [index1, index2] 6 */ 7 public int[] searchRange(int[] a, int target) { 8 if (a == null || a.length == 0) { 9 return new int[]{-1, -1}; 10 } 11 int[] result = new int[2]; 12 result[0] = getFirstTarget(a, target, 0, a.length - 1); 13 result[1] = getLastTarget(a, target, 0, a.length - 1); 14 return result; 15 } 16 public int getFirstTarget(int[] a, int target, int start, int end) { 17 if (a == null || a.length == 0 || start > end) { 18 return -1; 19 } 20 while (start <= end) { 21 int mid = start + (end - start) / 2; 22 if (a[mid] == target) { 23 //判断是否为第一个的条件 24 if (mid == 0 || mid > 0 && a[mid - 1] != target) { 25 return mid; 26 } else { 27 end = mid - 1; 28 } 29 } else if (a[mid] > target) { 30 end = mid - 1; 31 } else { 32 start = mid + 1; 33 } 34 } 35 return -1; 36 } 37 public int getLastTarget(int[] a, int target, int start, int end) { 38 if (a == null || a.length == 0 || start > end) { 39 return -1; 40 } 41 while (start <= end) { 42 int mid = start + (end - start) / 2; 43 if (a[mid] == target) { 44 //判断是否为最后一个的条件 45 if (mid == a.length - 1 || mid < a.length - 1 && a[mid + 1] != target) { 46 return mid; 47 } else { 48 start = mid + 1; 49 } 50 } else if (a[mid] > target) { 51 end = mid - 1; 52 } else { 53 start = mid + 1; 54 } 55 } 56 return -1; 57 } 58 }
7. Two Interview Cases
88. Lowest Common Ancestor(递归,出口为左子树或者右子树中存在任意一个节点则返回)
1 /** 2 * Definition of TreeNode: 3 * public class TreeNode { 4 * public int val; 5 * public TreeNode left, right; 6 * public TreeNode(int val) { 7 * this.val = val; 8 * this.left = this.right = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /** 14 * @param root: The root of the binary search tree. 15 * @param A and B: two nodes in a Binary. 16 * @return: Return the least common ancestor(LCA) of the two nodes. 17 */ 18 public TreeNode lowestCommonAncestor(TreeNode root, TreeNode node1, TreeNode node2) { 19 //找到其中一个点则返回 20 if (root == null || root == node1 || root == node2) { 21 return root; 22 } 23 TreeNode left = lowestCommonAncestor(root.left, node1, node2); 24 TreeNode right = lowestCommonAncestor(root.right, node1, node2); 25 if (left != null && right != null) { 26 //在左子树中找到了其中一个节点,在右子树中找到了另一个节点 27 return root; 28 } 29 if (left != null) { 30 return left; 31 } 32 if (right != null) { 33 return right; 34 } 35 return null; 36 } 37 }
54.String to Integer II (注意各种输入的情况:空格、符号,以及数字是否溢出)
1 public class Solution { 2 /** 3 * @param str: A string 4 * @return An integer 5 */ 6 public int atoi(String str) { 7 if (str == null || str.length() == 0) { 8 return 0; 9 } 10 int index = 0; 11 int sum = 0; 12 //sign必须为1,因为如果没有符号的话便是正的 13 int sign = 1; 14 //除去数字之前的空格 15 while (index < str.length() && str.charAt(index) == ' ') { 16 index++; 17 } 18 //确定数字的符号,若输入多个符号则输入有误 19 if (index < str.length() && (str.charAt(index) == '+' || str.charAt(index) == '-')) { 20 sign = str.charAt(index) == '+' ? 1 : -1; 21 index++; 22 } 23 //判断数字是否溢出 24 while (index < str.length() && str.charAt(index) >= '0' && str.charAt(index) <= '9' && str.charAt(index) != '.') { 25 int num = str.charAt(index) - '0'; 26 if (sum > Integer.MAX_VALUE / 10 || (sum == Integer.MAX_VALUE / 10 && num > Integer.MAX_VALUE % 10)) { 27 return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE; 28 } 29 sum = sum * 10 + num; 30 index++; 31 } 32 return sum * sign; 33 } 34 }
8. English Version Only
112. Remove Duplicates from Sorted List(思路:从重复节点的第一个节点开始处理,使得他的下一节点跳过与它值相同的节点)
1 /** 2 * Definition for ListNode 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { 7 * val = x; 8 * next = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /** 14 * @param ListNode head is the head of the linked list 15 * @return: ListNode head of linked list 16 */ 17 public static ListNode deleteDuplicates(ListNode head) { 18 if (head == null) { 19 return head; 20 } 21 //remove duplicates but appear once, so we should process the first node 22 //of duplicates 23 ListNode cur = head; 24 while (cur.next != null) { 25 if (cur.val == cur.next.val) { 26 cur.next = cur.next.next; 27 } else { 28 cur = cur.next; 29 } 30 } 31 return head; 32 } 33 }
113. Remove Duplicates from Sorted List II (思路:从重复节点的第一个节点的前一个节点开始处理,使得他的下一节点跳过与重复节点值相同的节点)
1 /** 2 * Definition for ListNode 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { 7 * val = x; 8 * next = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /** 14 * @param ListNode head is the head of the linked list 15 * @return: ListNode head of the linked list 16 */ 17 public static ListNode deleteDuplicates(ListNode head) { 18 if (head == null || head.next == null) { 19 return head; 20 } 21 //we need a dummy to save the head, and this is the code template 22 ListNode dummy = new ListNode(0); 23 dummy.next = head; 24 ListNode cur = dummy; 25 //we should process the node before the first duplicate 26 while (cur.next != null && cur.next.next != null) { 27 if (cur.next.val == cur.next.next.val) { 28 int dupValue = cur.next.val; 29 while (cur.next != null && cur.next.val == dupValue) { 30 cur.next = cur.next.next; 31 } 32 } else { 33 cur = cur.next; 34 } 35 } 36 return dummy.next; 37 } 38 }
69. Binary Tree Level Order Traversal (思路:利用queue的先进先出)
1 /** 2 * Definition of TreeNode: 3 * public class TreeNode { 4 * public int val; 5 * public TreeNode left, right; 6 * public TreeNode(int val) { 7 * this.val = val; 8 * this.left = this.right = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /** 14 * @param root: The root of binary tree. 15 * @return: Level order a list of lists of integer 16 */ 17 public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) { 18 //1.边界判断 19 ArrayList<ArrayList<Integer>> arrList = new ArrayList<>(); 20 if (root == null) { 21 return arrList; 22 } 23 //2.Queue是个接口,能通过LinkedList实现不能通过ArrayList实现 24 Queue<TreeNode> queue = new LinkedList<TreeNode>(); 25 queue.offer(root); 26 //3.循环体 27 while (!queue.isEmpty()) { 28 ArrayList<Integer> level = new ArrayList<>(); 29 int qSize = queue.size(); //注意,不能直接写入for循环 i < queue.size(),否则会因为后期的offer操作改变 30 for (int i = 0; i < qSize; i++) { 31 TreeNode head = queue.poll(); //poll()获取头部,并从队列中移除头部 32 level.add(head.val); 33 if (head.left != null) { 34 queue.offer(head.left); 35 } 36 if (head.right != null) { 37 queue.offer(head.right); 38 } 39 } 40 arrList.add(level); 41 } 42 return arrList; 43 } 44 }
50. Product of Array Exclude Itself (思路:分成前后两部分去乘)
1 public class Solution { 2 /** 3 * @param A: Given an integers array A 4 * @return: A Long array B and B[i]= A[0] * ... * A[i-1] * A[i+1] * ... * A[n-1] 5 */ 6 public ArrayList<Long> productExcludeItself(ArrayList<Integer> a) { 7 ArrayList<Long> arrList = new ArrayList<>(); 8 if (a == null || a.size() == 0) { 9 return arrList; 10 } 11 int len = a.size(); 12 long[] array = new long[len]; 13 long[] array1 = new long[len]; 14 for (int i = 0; i < len; i++) { 15 array[i] = a.get(i); 16 } 17 array1 = multiply(array, array1); 18 for (int i = 0; i < len; i++) { 19 arrList.add(array1[i]); 20 } 21 return arrList; 22 } 23 public long[] multiply(long[] array, long[] array1) { 24 //divid two parts to multiply 25 int len = array.length; 26 array1[0] = 1; 27 for (int i = 1; i < len; i++) { 28 array1[i] = array1[i - 1] * array[i - 1]; 29 } 30 long temp = 1; 31 for (int i = len - 2; i >= 0; i--) { 32 temp = temp * array[i + 1]; 33 array1[i] = array1[i] * temp; 34 } 35 return array1; 36 } 37 }
1 public class Solution { 2 /** 3 * @param A: Given an integers array A 4 * @return: A Long array B and B[i]= A[0] * ... * A[i-1] * A[i+1] * ... * A[n-1] 5 */ 6 public ArrayList<Long> productExcludeItself(ArrayList<Integer> a) { 7 ArrayList<Long> result = new ArrayList<>(); 8 if (a == null || a.size() == 0) { 9 return result; 10 } 11 long[] A = new long[a.size()]; 12 for (int i = 0; i < a.size(); i++) { 13 A[i] = a.get(i); 14 } 15 long[] B = new long[a.size()]; 16 B = multiply(A, B); 17 for (int i = 0; i < B.length; i++) { 18 result.add(B[i]); 19 } 20 return result; 21 } 22 public long[] multiply(long[] A, long[] B) { 23 B[0] = 1; 24 //分两步进行:先乘上C[i] 25 for (int i = 1; i < A.length; i++) { 26 B[i] = B[i - 1] * A[i - 1]; 27 } 28 long temp = 1; 29 //再乘上D[i] 30 for (int i = A.length - 2; i >= 0; i--) { 31 temp *= A[i + 1]; 32 B[i] = B[i] * temp; 33 } 34 return B; 35 } 36 }
71. Binary Tree Zigzag Level Order Traversal (思路:建立两个栈分别用来保存两个深度的节点,如果深度是偶数,先加入left,否则先加入right)
1 /** 2 * Definition of TreeNode: 3 * public class TreeNode { 4 * public int val; 5 * public TreeNode left, right; 6 * public TreeNode(int val) { 7 * this.val = val; 8 * this.left = this.right = null; 9 * } 10 * } 11 */ 12 13 14 public class Solution { 15 /** 16 * @param root: The root of binary tree. 17 * @return: A list of lists of integer include 18 * the zigzag level order traversal of its nodes' values 19 */ 20 public ArrayList<ArrayList<Integer>> zigzagLevelOrder(TreeNode root) { 21 ArrayList<ArrayList<Integer>> result = new ArrayList<>(); 22 if (root == null) { 23 return result; 24 } 25 Stack<TreeNode> curLevel = new Stack<>(); 26 Stack<TreeNode> nextLevel = new Stack<>(); 27 Stack<TreeNode> temp = new Stack<>(); 28 //define two stacks to save the node of current level and next level respectively. 29 curLevel.push(root); 30 boolean oddOrEven = true; 31 //when the num of elements is odd, push the left, else push the right 32 while (!curLevel.isEmpty()) { 33 ArrayList<Integer> curResult = new ArrayList<>(); 34 while (!curLevel.isEmpty()) { 35 TreeNode node = curLevel.pop(); 36 curResult.add(node.val); 37 if (oddOrEven) { 38 if (node.left != null) { 39 nextLevel.push(node.left); 40 } 41 if (node.right != null) { 42 nextLevel.push(node.right); 43 } 44 } else { 45 if (node.right != null) { 46 nextLevel.push(node.right); 47 } 48 if (node.left != null) { 49 nextLevel.push(node.left); 50 } 51 } 52 } 53 temp = curLevel; 54 curLevel = nextLevel; 55 nextLevel = temp; 56 oddOrEven = !oddOrEven; 57 result.add(curResult); 58 } 59 return result; 60 } 61 }
1 /** 2 * Definition of TreeNode: 3 * public class TreeNode { 4 * public int val; 5 * public TreeNode left, right; 6 * public TreeNode(int val) { 7 * this.val = val; 8 * this.left = this.right = null; 9 * } 10 * } 11 */ 12 13 14 public class Solution { 15 /** 16 * @param root: The root of binary tree. 17 * @return: A list of lists of integer include 18 * the zigzag level order traversal of its nodes' values 19 */ 20 public List<List<Integer>> zigzagLevelOrder(TreeNode root) { 21 List<List<Integer>> result = new ArrayList<>(); 22 if (root == null) { 23 return result; 24 } 25 //建立一个栈保存当前节点 26 Stack<TreeNode> curLevel = new Stack<>(); 27 //一个指示符向量指示添加入栈的方向 28 boolean change = true; 29 curLevel.push(root); 30 while (!curLevel.isEmpty()) { 31 List<Integer> tempList = new ArrayList<>(); 32 int stackSize = curLevel.size(); 33 //建立一个栈保存下一层极的节点 34 Stack<TreeNode> nextLevel = new Stack<>(); 35 for (int i = 0; i < stackSize; i++) { 36 TreeNode temp = curLevel.pop(); 37 tempList.add(temp.val); 38 if (change) { 39 if (temp.left != null) { 40 nextLevel.push(temp.left); 41 } 42 if (temp.right != null) { 43 nextLevel.push(temp.right); 44 } 45 } else { 46 if (temp.right != null) { 47 nextLevel.push(temp.right); 48 } 49 if (temp.left != null) { 50 nextLevel.push(temp.left); 51 } 52 } 53 } 54 curLevel = nextLevel; 55 change = !change; 56 result.add(tempList); 57 } 58 return result; 59 } 60 }
1 /** 2 * Definition of TreeNode: 3 * public class TreeNode { 4 * public int val; 5 * public TreeNode left, right; 6 * public TreeNode(int val) { 7 * this.val = val; 8 * this.left = this.right = null; 9 * } 10 * } 11 */ 12 13 14 public class Solution { 15 /** 16 * @param root: The root of binary tree. 17 * @return: A list of lists of integer include 18 * the zigzag level order traversal of its nodes' values 19 */ 20 public List<List<Integer>> zigzagLevelOrder(TreeNode root) { 21 //跟层次遍历一样,不过间隔一次进行一次反转操作就行Collections.reverse(tempList) 22 List<List<Integer>> result = new ArrayList<>(); 23 if (root == null) { 24 return result; 25 } 26 Queue<TreeNode> queue = new LinkedList<>(); 27 queue.offer(root); 28 boolean flag = false; 29 while (!queue.isEmpty()) { 30 int queueSize = queue.size(); 31 ArrayList<Integer> tempList = new ArrayList<>(); 32 for (int i = 0; i < queueSize; i++) { 33 TreeNode temp = queue.poll(); 34 tempList.add(temp.val); 35 if (temp.left != null) { 36 queue.offer(temp.left); 37 } 38 if (temp.right != null) { 39 queue.offer(temp.right); 40 } 41 } 42 if (flag) { 43 Collections.reverse(tempList); 44 } 45 flag = !flag; 46 result.add(tempList); 47 } 48 return result; 49 } 50 }
7.Binary Tree Serialization (思路:选择一个字符来表示为空的节点,然后将节点用逗号分开,反序列化的时候根据字符将节点分开)
1 /** 2 * Definition of TreeNode: 3 * public class TreeNode { 4 * public int val; 5 * public TreeNode left, right; 6 * public TreeNode(int val) { 7 * this.val = val; 8 * this.left = this.right = null; 9 * } 10 * } 11 */ 12 class Solution { 13 /** 14 * This method will be invoked first, you should design your own algorithm 15 * to serialize a binary tree which denote by a root node to a string which 16 * can be easily deserialized by your own "deserialize" method later. 17 */ 18 public String serialize(TreeNode root) { 19 StringBuilder sb = new StringBuilder(); 20 buildString(root, sb); 21 return sb.toString(); 22 } 23 private void buildString(TreeNode root, StringBuilder sb) { 24 if (root == null) { 25 sb.append("$,"); 26 } else { 27 sb.append(root.val).append(","); 28 buildString(root.left, sb); 29 buildString(root.right, sb); 30 } 31 } 32 /** 33 * This method will be invoked second, the argument data is what exactly 34 * you serialized at method "serialize", that means the data is not given by 35 * system, it's given by your own serialize method. So the format of data is 36 * designed by yourself, and deserialize it here as you serialize it in 37 * "serialize" method. 38 */ 39 public TreeNode deserialize(String data) { 40 Deque<String> nodes = new LinkedList<>(); 41 nodes.addAll(Arrays.asList(data.split(","))); 42 return buildTree(nodes); 43 } 44 private TreeNode buildTree(Deque<String> nodes) { 45 // we need the deque class to get the method of remove(); 46 String val = nodes.remove(); 47 if (val.equals("$")) { 48 return null; 49 } else { 50 TreeNode root = new TreeNode(Integer.valueOf(val)); 51 root.left = buildTree(nodes); 52 root.right = buildTree(nodes); 53 return root; 54 } 55 } 56 }
192. Wildcard Matching (思路:定义两个指针,并着重处理模式中为* 的情况)
1 public class Solution { 2 /** 3 * @param s: A string 4 * @param p: A string includes "?" and "*" 5 * @return: A boolean 6 */ 7 public boolean isMatch(String str, String pat) { 8 //定义四个指针,两个分别指向str和pat,另外两个分别表示*的位置以及 9 int indexP = 0; 10 int indexS = 0; 11 int indexStar = -1; 12 int indexMatch = 0; 13 while (indexS < str.length()) { 14 //当两个指针指向完全相同的字符或者p指向的是?时 15 if (indexP < pat.length() && (pat.charAt(indexP) == '?' || str.charAt(indexS) == pat.charAt(indexP))) { 16 indexP++; 17 indexS++; 18 //如果字符不同也没有?,但是在p中遇到的是*,那么记录下*的位置,但是不改变s的指针 19 } else if (indexP < pat.length() && pat.charAt(indexP) == '*') { 20 indexStar = indexP; 21 indexP++; 22 //遇到*后,用indexMatch记录匹配到的s的位置,和不用*匹配的s字符串区分 23 indexMatch = indexS; 24 //如果字符不同也没有?,p指向的也不是*,但是之前遇到*的话,我们可以从indexMatch继续匹配任意字符 25 } else if (indexStar != -1) { 26 //如果用上一个*匹配,那么p应该退回上一个*的后面 27 indexP = indexStar + 1; 28 //用*匹配的位置递增 29 indexMatch++; 30 //s退回到*匹配位置 31 indexS = indexMatch; 32 } else { 33 return false; 34 } 35 } 36 // 因为1个*能匹配无限序列,如果p末尾有多个*,我们都要跳过 37 while (indexP < pat.length() && pat.charAt(indexP) == '*') { 38 indexP++; 39 } 40 return indexP == pat.length(); 41 } 42 }
102. Linked List Cycle(思路: 定义一快一慢两个指针,如果最后两个指针相遇,说明存在环)
1 /** 2 * Definition for ListNode. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int val) { 7 * this.val = val; 8 * this.next = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /** 14 * @param head: The first node of linked list. 15 * @return: True if it has a cycle, or false 16 */ 17 public boolean hasCycle(ListNode head) { 18 //!!!!!!!!!!!!!!!!!!!!!!!!!! 19 //java.lang.NullPointerException this only occurs in if or while etc, means 20 //only occurs when judging the conditions, doesn't occur in assignment 21 //statement(赋值语句)except fast = fast.next.next; 22 //简单来说就是node = node.next这个语句中node不可以为空,但是node.next可以为空 23 //!!!!!!!!!!!!!!!!!!!!!!!!!! 24 if (head == null || head.next == null) { 25 return false; 26 } 27 //define two points, slow and fast, if they can meet each other, means 28 //there is a cycle in this list. 29 ListNode slow = head; 30 ListNode fast = head.next; 31 while (slow != null && fast != null) { 32 if (slow == fast) { 33 return true; 34 } 35 slow = slow.next; 36 fast = fast.next; 37 if (fast != null) { 38 fast = fast.next; 39 } 40 } 41 return false; 42 } 43 }
103. Linked List Cycle II (思路:根据102找到相遇的节点,这个节点必然为环路中的节点,然后根据此节点获得环路的节点个数n,然后定义一快一慢两个指针,快指针先走n步,然后两个一起走,相遇的节点就是环开始的节点)
1 /** 2 * Definition for ListNode. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int val) { 7 * this.val = val; 8 * this.next = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /** 14 * @param head: The first node of linked list. 15 * @return: The node where the cycle begins. 16 * if there is no cycle, return null 17 */ 18 public ListNode detectCycle(ListNode head) { 19 int num = getNumOfNodeInLoop(head); 20 if (num == 0) { 21 return null; 22 } 23 ListNode first = head; 24 ListNode second = head; 25 for (int i = 0; i < num; i++) { 26 first = first.next; 27 } 28 while (first != second) { 29 first = first.next; 30 second = second.next; 31 } 32 return first; 33 } 34 public ListNode findMeetingNode(ListNode head) { 35 //if there is no node or one node in list, there will not be cycle 36 if (head == null || head.next == null) { 37 return null; 38 } 39 //define two points, slow and fast, when they meet each other, 40 //this means there is cycle 41 ListNode slow = head; 42 //if code is ListNode slow = head.next, this solution is accepted, but i 43 //think it's wrong! because it doesn't include the instance of (head == head.next) 44 ListNode fast = slow.next; 45 while (slow != null && fast != null) { 46 if (slow == fast) { 47 return slow; 48 } 49 slow = slow.next; 50 fast = fast.next; 51 if (fast != null) { 52 fast = fast.next; 53 } 54 } 55 return null; 56 } 57 public int getNumOfNodeInLoop(ListNode head) { 58 if (head == null || head.next == null) { 59 return 0; 60 } 61 //meetingNode must be one of nodes in loop, 62 //so from meetingNode to meetingNode(second time) 63 //is the num of nodes in loop 64 ListNode meetingNode = findMeetingNode(head); 65 if (meetingNode == null) { 66 return 0; 67 } 68 int num = 1; 69 ListNode node = meetingNode; 70 while (node.next != meetingNode) { 71 node = node.next; 72 num++; 73 } 74 return num; 75 } 76 }
81. Data Stream Median(思路:建立最大堆和最小堆,最大堆的堆顶就是中位数)
1 public class Solution { 2 /** 3 * @param nums: A list of integers. 4 * @return: the median of numbers 5 */ 6 public int[] medianII(int[] nums) { 7 if (nums == null || nums.length == 0) { 8 return new int[0]; 9 } 10 int len = nums.length; 11 PriorityQueue<Integer> maxHeap = new PriorityQueue<>(len, Collections.reverseOrder()); 12 PriorityQueue<Integer> minHeap = new PriorityQueue<>(len); 13 int[] result = new int[len]; 14 for (int i = 0; i < nums.length; i++) { 15 //put first num in maxHeap 16 //然后根据大小加入最大堆和最小堆,再根据两个堆的数量进行 17 if (maxHeap.isEmpty() || nums[i] < maxHeap.peek()) { 18 maxHeap.add(nums[i]); //maxHeap.offer(nums[i]) is ok too. 19 } else { 20 minHeap.add(nums[i]); 21 } 22 if (minHeap.size() > maxHeap.size()) { 23 maxHeap.add(minHeap.poll()); 24 } 25 if (maxHeap.size() > minHeap.size() + 1) { 26 minHeap.add(maxHeap.poll()); 27 } 28 result[i] = maxHeap.peek(); 29 } 30 return result; 31 } 32 }
362. Sliding Window Maximum (思路:滑动窗口的最大值一直在队列的头部)
1 public class Solution { 2 /** 3 * @param nums: A list of integers. 4 * @return: The maximum number inside the window at each moving. 5 */ 6 public ArrayList<Integer> maxSlidingWindow(int[] nums, int k) { 7 ArrayList<Integer> result = new ArrayList<>(); 8 if (nums == null || nums.length == 0 || k == 0) { 9 return result; 10 } 11 Deque<Integer> deque = new ArrayDeque<>(); 12 for (int i = 0; i < k - 1; i++) { 13 inDeque(deque, nums[i]); 14 } 15 for (int i = k - 1; i < nums.length; i++) { 16 inDeque(deque, nums[i]); 17 result.add(deque.peekFirst()); 18 outDeque(deque, nums[i - (k - 1)]); 19 } 20 return result; 21 } 22 public void inDeque(Deque<Integer> deque, int num) { 23 //根据剑指offer的思路,滑动窗口的最大值在队列的首部 24 while (!deque.isEmpty() && deque.peekLast() < num) { 25 deque.pollLast(); 26 } 27 deque.offer(num); 28 } 29 public void outDeque(Deque<Integer> deque, int num) { 30 //accroding to the size of sliding windows 31 if (deque.peekFirst() == num) { 32 deque.pollFirst(); 33 } 34 } 35 }
public class Solution {
/**
* @param A a string
* @param B a string
* @return a boolean
*/
public boolean Permutation(String a, String b) {
//注意如何将字符转化为ackii码(直接强制转换),以及判断整个数组是否为0(遍历)
if (a == null || b == null) {
return a == b;
}
if (a.length() != b.length()) {
return false;
}
int[] nums = new int[150];
for (int i = 0; i < a.length(); i++) {
nums[(int)a.charAt(i)]++;
}
for (int i = 0; i < b.length(); i++) {
nums[(int)b.charAt(i)]--;
}
for (int i = 0; i < nums.length; i++) {
if (nums[i] != 0) {
return false;
}
}
return true;
}
}