1. Two Sum
思路:遍历整个数组,将target减去当前元素的值作为key,其位置作为value,这样key即表示另外一个所需的数值;当找到时,result数组的两个数值分别为hashMap中的value值,当前的位置i
1 public class Solution { 2 public int[] twoSum(int[] nums, int target) { 3 HashMaphash = new HashMap<>(); 4 for (int i = 0; i < nums.length; i++) { 5 if (hash.containsKey(nums[i])) { 6 int[] result = {hash.get(nums[i]), i}; 7 return result; 8 } 9 hash.put(target - nums[i], i); 10 } 11 int[] result = {}; 12 return result; 13 } 14 }
3. Longest Substring Without Repeating Characters
1 class Solution { 2 public int lengthOfLongestSubstring(String s) { 3 if (s == null || s.length() == 0) { 4 return 0; 5 } 6 Mapmapping = new HashMap<>(); 7 int max = 0; 8 for (int i = 0, j = 0; i < s.length(); i++) { 9 if (mapping.containsKey(s.charAt(i))) { 10 j = Math.max(j, mapping.get(s.charAt(i)) + 1); 11 } 12 mapping.put(s.charAt(i), i); 13 max = Math.max(max, i - j + 1); 14 } 15 return max; 16 } 17 }
方法二:滑动窗口算法,比较巧妙
1 class Solution { 2 public int lengthOfLongestSubstring(String s) { 3 if (s == null || s.length() == 0) { 4 return 0; 5 } 6 HashMaphash = new HashMap<>(); 7 int start = 0; 8 int end = 0; 9 int len = 0; 10 int counter = 0; 11 while (end < s.length()) { 12 char c = s.charAt(end); 13 hash.put(c, hash.getOrDefault(c, 0) + 1); 14 if (hash.get(c) > 1) { 15 counter++; 16 } 17 end++; 18 while (counter > 0) { 19 char tempc = s.charAt(start); 20 if (hash.get(tempc) > 1) { 21 counter--; 22 } 23 hash.put(tempc, hash.get(tempc) - 1); 24 start++; 25 } 26 len = Math.max(len, end - start); 27 } 28 return len; 29 } 30 }
7. Reverse Integer
思路:首先取余得到个位,此题要求超出整数范围返回0,故设置newResult,解释在注释里(记住),然后依次得到各个位
1 public class Solution { 2 public int reverse(int x) { 3 int result = 0; 4 while (x != 0) { 5 int tail = x % 10; 6 int newResult = result * 10 + tail; 7 // If overflow exists, the new result will not equal previous one. 8 if ((newResult - tail) / 10 != result) { 9 return 0; 10 } 11 result = newResult; 12 x = x / 10; 13 } 14 return result; 15 } 16 }
9. Palindrome Number
思路:只需要判断x的一半数值即可,因此溢出情况不需要考虑
1 public class Solution { 2 public boolean isPalindrome(int x) { 3 if (x < 0 || (x != 0 && x % 10 == 0)) { 4 return false; 5 } 6 int rev = 0; 7 while (x > rev) { 8 rev = rev * 10 + x % 10; 9 x = x / 10; 10 } 11 return (x == rev || x == rev / 10); 12 } 13 }
注意:特殊情况,负数与个位为零(0除外)一定不是回文数
13. Roman to Integer
思路:将每一位罗马数字转换成整数值存入到数组nums中,遍历nums数组,如果此时的数值大于下一位数值时,则要相减,否则相加
1 public class Solution { 2 public int romanToInt(String s) { 3 int[] nums = new int[s.length()]; 4 for (int i = 0; i < s.length(); i++) { 5 switch (s.charAt(i)) { 6 case 'M': 7 nums[i] = 1000; 8 break; 9 case 'D': 10 nums[i] = 500; 11 break; 12 case 'C': 13 nums[i] = 100; 14 break; 15 case 'L': 16 nums[i] = 50; 17 break; 18 case 'X' : 19 nums[i] = 10; 20 break; 21 case 'V': 22 nums[i] = 5; 23 break; 24 case 'I': 25 nums[i] = 1; 26 break; 27 } 28 } 29 int sum = 0; 30 for (int i = 0; i < nums.length - 1; i++) { 31 if (nums[i] < nums[i + 1]) { 32 sum -= nums[i]; 33 } else { 34 sum += nums[i]; 35 } 36 } 37 return sum + nums[nums.length - 1]; 38 } 39 }
14. Longest Common Prefix
思路:首先将前缀默认为数组中的第一个元素,遍历数组,如果此前缀不是当前元素的前缀,则逐个去除末尾的字符直到符合
1 public class Solution { 2 public String longestCommonPrefix(String[] strs) { 3 if (strs.length == 0 || strs == null) { 4 return ""; 5 } 6 String pre = strs[0]; 7 for (int i = 1; i < strs.length; i++) { 8 while (strs[i].indexOf(pre) != 0) { 9 pre = pre.substring(0, pre.length() - 1); 10 } 11 } 12 return pre; 13 } 14 }
20. Valid Parentheses
思路:将字符串变为字符数组进行遍历,如果遇到前括号,则在栈中放入其对应的后括号;如果遇到后括号,则取出栈中的元素,如果不同则不是合法的
1 public class Solution { 2 public boolean isValid(String s) { 3 Stackstack = new Stack<>(); 4 for (char c : s.toCharArray()) { 5 if (c == '(') { 6 stack.push(')'); 7 } else if (c == '{') { 8 stack.push('}'); 9 } else if (c == '[') { 10 stack.push(']'); 11 } else if (stack.isEmpty() || stack.pop() != c) { 12 return false; 13 } 14 } 15 return stack.isEmpty(); 16 } 17 }
注意:如果栈为空,而字符数组没有遍历完,则表明多余后括号一定不合法;最后返回时,如果栈不为空,则表明多余前括号,也不合法
21. Merge Two Sorted Lists
思路:对于链表问题采用dummy node方法,比较两个链表的元素组合为新的链表,注意以下几点即可:
- 每次记得更新head = head.next
- 当其中一个链表没有全部merge时,将其剩下的全部merge到新的链表即可
1 /** 2 * Definition for singly-linked list. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { val = x; } 7 * } 8 */ 9 public class Solution { 10 public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 11 ListNode dummy = new ListNode(0); 12 ListNode head = dummy; 13 while (l1 != null && l2 != null) { 14 if (l1.val > l2.val) { 15 head.next = l2; 16 l2 = l2.next; 17 } else { 18 head.next = l1; 19 l1 = l1.next; 20 } 21 head = head.next; 22 } 23 // 当有一个ListNode不为null时,直接将其作为head.next即可 24 if (l1 != null) { 25 head.next = l1; 26 } else { 27 head.next = l2; 28 } 29 return dummy.next; 30 } 31 }
26. Remove Duplicates from Sorted Array
思路:如果数组的当前元素与前一个元素不相等时,一定不是重复元素,则将其赋值给nums[index++]即可实现原地更新数组,并记录不重复元素的个数
1 public class Solution { 2 public int removeDuplicates(int[] nums) { 3 if (nums == null || nums.length == 0) { 4 return 0; 5 } 6 int index = 1; 7 for (int i = 1; i < nums.length; i++) { 8 if (nums[i] != nums[i - 1]) { 9 nums[index++] = nums[i]; 10 } 11 } 12 return index; 13 } 14 }
27. Remove Element
思路:与上道题目一样
1 public class Solution { 2 public int removeElement(int[] nums, int val) { 3 if (nums == null || nums.length == 0) { 4 return 0; 5 } 6 int index = 0; 7 for (int i = 0; i < nums.length; i++) { 8 if (nums[i] != val) { 9 nums[index++] = nums[i]; 10 } 11 } 12 return index; 13 } 14 }
28. Implement strStr()
思路:两种方法,第一种简单,掌握第二种方法
1 public class Solution { 2 public int strStr(String haystack, String needle) { 3 if (haystack == null || needle == null) { 4 return -1; 5 } 6 for (int i = 0; i < haystack.length() - needle.length() + 1; i++) { 7 if (haystack.substring(i, i + needle.length()).equals(needle)) { 8 return i; 9 } 10 } 11 return -1; 12 } 13 }
1 public class Solution { 2 int base = 1000000; 3 public int strStr(String haystack, String needle) { 4 if (haystack == null || needle == null) { 5 return -1; 6 } 7 if (needle.length() == 0) { 8 return 0; 9 } 10 int m = needle.length(); 11 int power = 1; 12 for (int i = 0; i < m; i++) { 13 power = (power * 33) % base; 14 } 15 int needleCode = 0; 16 for (int i = 0; i < m; i++) { 17 needleCode = (needleCode * 33 + needle.charAt(i)) % base; 18 } 19 int hashCode = 0; 20 for (int i = 0; i < haystack.length(); i++) { 21 hashCode = (hashCode * 33 + haystack.charAt(i)) % base; 22 if (i < m - 1) { 23 continue; 24 } 25 if (i >= m) { 26 hashCode = hashCode - (haystack.charAt(i - m) * power) % base; 27 if (hashCode < 0) { 28 hashCode += base; 29 } 30 } 31 if (hashCode == needleCode) { 32 if (haystack.substring(i - m + 1, i + 1).equals(needle)) { 33 return i - m + 1; 34 } 35 } 36 } 37 return -1; 38 } 39 }
注意:
- power也要取余;计算hashCode时范围的选取
35. Search Insert Position
思路:采用二分法搜索目标数字,最后target只可能存在三种情况,故最后分三种分别返回即可
1 public class Solution { 2 public int searchInsert(int[] nums, int target) { 3 int start = 0; 4 int end = nums.length - 1; 5 while (start + 1 < end) { 6 int mid = start + (end - start) / 2; 7 if (nums[mid] == target) { 8 return mid; 9 } else if (nums[mid] < target) { 10 start = mid; 11 } else { 12 end = mid; 13 } 14 } 15 if (nums[start] >= target) { 16 return start; 17 } else if (nums[end] >= target) { 18 return end; 19 } else { 20 return end + 1; 21 } 22 } 23 }
注意:最后三种情况开始没有想到
49. Group Anagrams
思路:
1 class Solution { 2 public List> groupAnagrams(String[] strs) { 3 List
> res = new ArrayList<>(); 4 if (strs.length == 0 || strs == null) { 5 return res; 6 } 7 HashMap
> mapping = new HashMap<>(); 8 ArrayList list = new ArrayList<>(); 9 for (String str: strs) { 10 char[] chars = str.toCharArray(); 11 Arrays.sort(chars); 12 if (!mapping.containsKey(new String(chars))) { 13 mapping.put(new String(chars), new ArrayList<>()); 14 } 15 mapping.get(new String(chars)).add(str); 16 } 17 for (Map.Entry entry : mapping.entrySet()) { 18 String key = (String) entry.getKey(); 19 res.add(mapping.get(key)); 20 } 21 return res; 22 } 23 }
53. Maximum Subarray
思路:得出最大的子数组和,只要从开始到结束位置的子数组和减去前面子数组的最小和(初始为0,即小于0的子数组和),即可得到最大的子数组和
1 public class Solution { 2 public int maxSubArray(int[] nums) { 3 int max = Integer.MIN_VALUE; 4 int minSum = 0; 5 int sum = 0; 6 for (int i = 0; i < nums.length; i++) { 7 sum += nums[i]; 8 max = Math.max(max, sum - minSum); 9 minSum = Math.min(minSum, sum); 10 } 11 return max; 12 } 13 }
58. Length of Last Word
思路:比较简单,注意点看注释
1 public class Solution { 2 public int lengthOfLastWord(String s) { 3 char[] c = s.toCharArray(); 4 int len = s.length() - 1; 5 int num = 0; 6 // delete space 7 while (len >= 0 && c[len] == ' ') { 8 len--; 9 } 10 // find the length of last word 11 while (len >= 0 && c[len] != ' ') { 12 num++; 13 len--; 14 } 15 return num; 16 } 17 }
66. Plus One
思路:看程序即可
1 public class Solution { 2 public int[] plusOne(int[] digits) { 3 int len = digits.length; 4 int carry = 1; 5 for (int i = len - 1; i >= 0; i--) { 6 digits[i] += carry; 7 carry = digits[i] / 10; 8 digits[i] = digits[i] % 10; 9 if (carry == 0) { 10 return digits; 11 } 12 } 13 int[] res = new int[len + 1]; 14 res[0] = 1; 15 return carry == 0 ? digits : res; 16 } 17 }
67. Add Binary
思路:通过StringBuilder实现数字的添加,通过十进制相加然后取余可以得到二进制数字
技巧:通过减去字符串0可以得到其对应的数字
1 class Solution { 2 public String addBinary(String a, String b) { 3 StringBuilder sb = new StringBuilder(); 4 int i = a.length() - 1; 5 int j = b.length() - 1; 6 int carry = 0; 7 while (i >= 0 || j >= 0) { 8 int sum = carry; 9 if (i >= 0) { 10 sum += a.charAt(i--) - '0'; 11 } 12 if (j >= 0) { 13 sum += b.charAt(j--) - '0'; 14 } 15 sb.append(sum % 2); 16 carry = sum / 2; 17 } 18 if (carry != 0) { 19 sb.append(carry); 20 } 21 return sb.reverse().toString(); 22 } 23 }
69. Sqrt(x)
思路:采用二分法,比较简单
1 class Solution { 2 public int mySqrt(int x) { 3 if (x <= 1) { 4 return x; 5 } 6 long start = 0; 7 long end = x; 8 while (start + 1 < end) { 9 long mid = start + (end - start) / 2; 10 if (mid * mid == x) { 11 return (int) mid; 12 } else if (mid * mid < x) { 13 start = mid; 14 } else { 15 end = mid; 16 } 17 } 18 return (int) start; 19 } 20 }
注意:
1. 记得采用long类型
70. Climbing Stairs
思路:最简单的动态规划问题
1 class Solution { 2 public int climbStairs(int n) { 3 if (n <= 1) { 4 return n; 5 } 6 int[] result = new int[3]; 7 result[0] = 1; 8 result[1] = 1; 9 for (int i = 2; i <= n; i++) { 10 result[i % 3] = result[(i - 1) % 3] + result[(i - 2) % 3]; 11 } 12 return result[n % 3]; 13 } 14 }
76. Minimum Window Substring
思路:滑动窗口算法
1 class Solution { 2 public String minWindow(String s, String t) { 3 if (s.length() < t.length()) { 4 return ""; 5 } 6 HashMaphash = new HashMap<>(); 7 for (char c : t.toCharArray()) { 8 hash.put(c, hash.getOrDefault(c, 0) + 1); 9 } 10 int start = 0; 11 int end = 0; 12 int counter = hash.size(); 13 int len = Integer.MAX_VALUE; 14 int head = -1; 15 while (end < s.length()) { 16 char c = s.charAt(end); 17 if (hash.containsKey(c)) { 18 hash.put(c, hash.get(c) - 1); 19 if (hash.get(c) == 0) { 20 counter--; 21 } 22 } 23 end++; 24 while (counter == 0) { 25 char tempc = s.charAt(start); 26 if (hash.containsKey(tempc)) { 27 hash.put(tempc, hash.get(tempc) + 1); 28 if (hash.get(tempc) > 0) { 29 counter++; 30 } 31 } 32 if (end - start < len) { 33 len = end - start; 34 head = start; 35 } 36 start++; 37 } 38 } 39 if (head == -1) { 40 return ""; 41 } 42 return s.substring(head, head + len); 43 } 44 }
83. Remove Duplicates from Sorted List
思路:看discuss,很巧妙,每次讲head.next进行递归,如果当前head与head.next相等,直接返回head.next,否则返回head
1 /** 2 * Definition for singly-linked list. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { val = x; } 7 * } 8 */ 9 class Solution { 10 public ListNode deleteDuplicates(ListNode head) { 11 if (head == null || head.next == null) { 12 return head; 13 } 14 head.next = deleteDuplicates(head.next); 15 return head.val == head.next.val ? head.next : head; 16 } 17 }
88. Merge Sorted Array
思路:转换思路,从大到小开始寻找
1 class Solution { 2 public void merge(int[] nums1, int m, int[] nums2, int n) { 3 int i = m - 1; 4 int j = n - 1; 5 int len = m + n - 1; 6 while (i >= 0 && j >= 0) { 7 if (nums1[i] > nums2[j]) { 8 nums1[len--] = nums1[i--]; 9 } else { 10 nums1[len--] = nums2[j--]; 11 } 12 } 13 while (j >= 0) { 14 nums1[len--] = nums2[j--]; 15 } 16 } 17 }
注意:
1. 最后可能nums2没有merge完毕,要记得最后检查
2. while循环条件是&
98. Validate Binary Search Tree
方法一:中序遍历是递增序列(感觉比较难以理解)
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public boolean isValidBST(TreeNode root) { 12 if (root == null) { 13 return true; 14 } 15 Stackstack = new Stack<>(); 16 TreeNode cur = root; 17 TreeNode pre = null; 18 while (true) { 19 while (cur != null) { 20 stack.push(cur); 21 cur = cur.left; 22 } 23 if (stack.isEmpty()) { 24 break; 25 } 26 cur = stack.pop(); 27 if (pre != null && pre.val >= cur.val) { 28 return false; 29 } 30 pre = cur; 31 cur = cur.right; 32 } 33 return true; 34 } 35 }
方法二:用上下限定来递归(想法很好)
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public boolean isValidBST(TreeNode root) { 12 if (root == null) { 13 return true; 14 } 15 return helper(root, Long.MIN_VALUE, Long.MAX_VALUE); 16 } 17 private boolean helper(TreeNode root, long min, long max) { 18 if (root == null) { 19 return true; 20 } 21 if (root.val <= min || root.val >= max) { 22 return false; 23 } 24 return helper(root.left, min, root.val) && helper(root.right, root.val, max); 25 } 26 }
方法三:采用dfs
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 private class ResultType { 12 boolean isBST; 13 int maxValue; 14 int minValue; 15 ResultType(boolean isBST, int maxValue, int minValue) { 16 this.isBST = isBST; 17 this.maxValue = maxValue; 18 this.minValue = minValue; 19 } 20 } 21 public boolean isValidBST(TreeNode root) { 22 if (root == null) { 23 return true; 24 } 25 ResultType result = dfsHelper(root); 26 return result.isBST; 27 } 28 private ResultType dfsHelper(TreeNode root) { 29 if (root == null) { 30 return new ResultType(true, Integer.MIN_VALUE, Integer.MAX_VALUE); 31 } 32 ResultType left = dfsHelper(root.left); 33 ResultType right = dfsHelper(root.right); 34 if (!left.isBST || !right.isBST) { 35 return new ResultType(false, 0, 0); 36 } 37 if (root.left != null && left.maxValue >= root.val || root.right != null && right.minValue <= root.val) { 38 return new ResultType(false, 0, 0); 39 } 40 return new ResultType(true, Math.max(root.val, right.maxValue), Math.min(root.val, left.minValue)); 41 } 42 }
方法四:采取中序遍历的方法,但是用了一个全局变量,不建议使用
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 TreeNode pre = null; 12 public boolean isValidBST(TreeNode root) { 13 if (root == null) { 14 return true; 15 } 16 return helper(root); 17 } 18 private boolean helper(TreeNode root) { 19 if (root == null) { 20 return true; 21 } 22 if (!helper(root.left)) { 23 return false; 24 } 25 if (pre != null && root.val <= pre.val) { 26 return false; 27 } 28 pre = root; 29 if (!helper(root.right)) { 30 return false; 31 } 32 return true; 33 } 34 }
100. Same Tree
思路:采用分治法,注意一些特殊判断即可
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public boolean isSameTree(TreeNode p, TreeNode q) { 12 if (p == null && q == null) { 13 return true; 14 } else if (p == null) { 15 return false; 16 } else if (q == null) { 17 return false; 18 } else if (p.val != q.val) { 19 return false; 20 } 21 boolean left = isSameTree(p.left, q.left); 22 boolean right = isSameTree(p.right, q.right); 23 return left && right; 24 } 25 }
101. Symmetric Tree
思路:
第一种方法:采用队列,建立两个队列,分别存储左右子树,然后判断即可
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public boolean isSymmetric(TreeNode root) { 12 if (root == null) { 13 return true; 14 } 15 Queueleft = new LinkedList<>(); 16 Queue right = new LinkedList<>(); 17 left.offer(root); 18 right.offer(root); 19 while (!left.isEmpty() && !right.isEmpty()) { 20 TreeNode leftNode = left.poll(); 21 TreeNode rightNode = right.poll(); 22 if (leftNode == null && rightNode == null) { 23 continue; 24 } 25 if (leftNode != null && rightNode != null) { 26 if (leftNode.val != rightNode.val) { 27 return false; 28 } 29 left.offer(leftNode.left); 30 left.offer(leftNode.right); 31 right.offer(rightNode.right); 32 right.offer(rightNode.left); 33 } else { 34 return false; 35 } 36 } 37 return true; 38 } 39 }
注意:
- 第一步要将root节点放入左右子树所代表的队列中
- 当队列取出的节点全部为null,要接着判断直到队列为空
第二种方法:比较好理解,直接看答案
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public boolean isSymmetric(TreeNode root) { 12 if (root == null) { 13 return true; 14 } 15 return isSymmetricUtil(root, root); 16 } 17 private boolean isSymmetricUtil(TreeNode left, TreeNode right) { 18 if (left == null && right == null) { 19 return true; 20 } else if (left != null && right != null) { 21 return left.val == right.val && isSymmetricUtil(left.left, right.right) && isSymmetricUtil(left.right, right.left); 22 } 23 return false; 24 } 25 }
104. Maximum Depth of Binary Tree
思路:比较简单,第一种方法直接采用全局变量,第二种采用分治算法
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 private int depth; 12 public int maxDepth(TreeNode root) { 13 if (root == null) { 14 return 0; 15 } 16 helper(root, 1); 17 return depth; 18 } 19 private void helper(TreeNode node, int curDepth) { 20 if (node == null) { 21 return; 22 } 23 if (depth < curDepth) { 24 depth = curDepth; 25 } 26 helper(node.left, curDepth + 1); 27 helper(node.right, curDepth + 1); 28 } 29 }
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public int maxDepth(TreeNode root) { 12 if (root == null) { 13 return 0; 14 } 15 int left = maxDepth(root.left) + 1; 16 int right = maxDepth(root.right) + 1; 17 int depth = Math.max(left, right); 18 return depth; 19 } 20 }
105. Construct Binary Tree from Preorder and Inorder Traversal
思路:前序遍历的第一个点一定为根节点,然后去中序遍历中找根节点,这样就得到了左子树和右子树,进行遍历即可
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public TreeNode buildTree(int[] preorder, int[] inorder) { 12 if (preorder == null || preorder.length == 0) { 13 return null; 14 } 15 TreeNode root = construct(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1); 16 return root; 17 } 18 private TreeNode construct(int[] pre, int startPre, int endPre, int[] in, int startIn, int endIn) { 19 if (startPre > endPre || startIn > endIn) { 20 return null; 21 } 22 TreeNode root = new TreeNode(pre[startPre]); 23 for (int i = startIn; i <= endIn; i++) { 24 if (in[i] == pre[startPre]) { 25 root.left = construct(pre, startPre + 1, startPre + i - startIn, in, startIn, i - 1); 26 root.right = construct(pre, startPre + i - startIn + 1, endPre, in, i + 1, endIn); 27 } 28 } 29 return root; 30 } 31 }
注意:
1. 递归的结束条件
2. 每次递归时,左子树的区间
106. Construct Binary Tree from Inorder and Postorder Traversal
思路:与上道题目相同
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public TreeNode buildTree(int[] inorder, int[] postorder) { 12 if (inorder == null || inorder.length == 0) { 13 return null; 14 } 15 TreeNode root = construct(inorder, 0, inorder.length - 1, postorder, 0, postorder.length - 1); 16 return root; 17 } 18 private TreeNode construct(int[] in, int startIn, int endIn, int[] post, int startPost, int endPost) { 19 if (startIn > endIn || startPost > endPost) { 20 return null; 21 } 22 TreeNode root = new TreeNode(post[endPost]); 23 for (int i = startIn; i <= endIn; i++) { 24 if (in[i] == post[endPost]) { 25 root.left = construct(in, startIn, i - 1, post, startPost, startPost + i - startIn - 1); 26 root.right = construct(in, i + 1, endIn, post, startPost + i - startIn, endPost - 1); 27 } 28 } 29 return root; 30 } 31 }
107. Binary Tree Level Order Traversal II
思路:BFS,BFS一般需要都需要queue,将每一层的采用队列的方式取出
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public List> levelOrderBottom(TreeNode root) { 12 List
> result = new ArrayList<>(); 13 if (root == null) { 14 return result; 15 } 16 Queue
queue = new LinkedList<>(); 17 queue.offer(root); 18 while (!queue.isEmpty()) { 19 List level = new ArrayList<>(); 20 int size = queue.size(); 21 for (int i = 0; i < size; i++) { 22 TreeNode node = queue.poll(); 23 level.add(node.val); 24 if (node.left != null) { 25 queue.offer(node.left); 26 } 27 if (node.right != null) { 28 queue.offer(node.right); 29 } 30 } 31 result.add(level); 32 } 33 Collections.reverse(result); 34 return result; 35 } 36 }
108. Convert Sorted Array to Binary Search Tree
思路:看答案的
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public TreeNode sortedArrayToBST(int[] nums) { 12 if (nums == null || nums.length == 0) { 13 return null; 14 } 15 return helper(nums, 0, nums.length - 1); 16 } 17 private TreeNode helper(int[] nums, int start, int end) { 18 if (start > end) { 19 return null; 20 } 21 int mid = (end + start) >> 1; 22 TreeNode node = new TreeNode(nums[mid]); 23 node.left = helper(nums, start, mid - 1); 24 node.right = helper(nums, mid + 1, end); 25 return node; 26 } 27 }
110. Balanced Binary Tree
思路:分治算法,左右子树分别判断是否符合,从底向上逐步判断
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 private class ResultType { 12 boolean isBalanced; 13 int maxDepth; 14 public ResultType(boolean isBalanced, int maxDepth) { 15 this.isBalanced = isBalanced; 16 this.maxDepth = maxDepth; 17 } 18 } 19 public boolean isBalanced(TreeNode root) { 20 if (root == null) { 21 return true; 22 } 23 return helper(root).isBalanced; 24 } 25 private ResultType helper(TreeNode node) { 26 if (node == null) { 27 return new ResultType(true, 0); 28 } 29 ResultType left = helper(node.left); 30 ResultType right = helper(node.right); 31 if (!left.isBalanced || !right.isBalanced) { 32 return new ResultType(false, -1); 33 } 34 if (Math.abs(left.maxDepth - right.maxDepth) > 1) { 35 return new ResultType(false, -1); 36 } 37 return new ResultType(true, Math.max(left.maxDepth, right.maxDepth) + 1); 38 } 39 }
注意:
1. helper()函数要判断子节点
2. 最大深度不要忘记加1
111. Minimum Depth of Binary Tree
思路:从最末端的节点开始考虑
- 当发现子节点只有一个叶子节点,则当前节点的最小深度为两个节点的最小深度加1(空节点的深度为0)
- 当发现子节点的两个节点都不为0时,则取两个节点的最小深度加1为当前节点的最小深度
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public int minDepth(TreeNode root) { 12 if (root == null) { 13 return 0; 14 } 15 int left = minDepth(root.left); 16 int right = minDepth(root.right); 17 return (left == 0 || right == 0) ? left + right + 1 : Math.min(left, right) + 1; 18 } 19 }
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public int minDepth(TreeNode root) { 12 if (root == null) { 13 return 0; 14 } 15 if (root.left == null) { 16 return minDepth(root.right) + 1; 17 } 18 if (root.right == null) { 19 return minDepth(root.left) + 1; 20 } 21 return Math.min(minDepth(root.right), minDepth(root.left)) + 1; 22 } 23 }
112. Path Sum
思路:开始没想到,看答案,从根节点到叶子节点的路径,条件为必须为叶子节点而且此时目标和减去当前节点的值为零,如果已经为叶子节点却没有找到,则返回false,但是只要存在一条路径即可,所以采用或条件
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public boolean hasPathSum(TreeNode root, int sum) { 12 if (root == null) { 13 return false; 14 } 15 if (root.left == null && root.right == null && sum - root.val == 0) { 16 return true; 17 } 18 return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val); 19 } 20 }
115. Distinct Subsequences
思路:维护一个数组mem,其中行数为T字符串的长度加1(包含空字符串),列数为S字符串的长度加1(包含空字符串),数组内的数值如下:
- 第一行初始化为1,由于空字符串是任何字符串的子序列
- 第一列除第一行元素外,全部为0,由于任何非空字符串不可能是空字符串的子序列
- 当S字符串的当前字符与T字符串的当前字符相等的时候,此时当前数组的元素数值为当前行前一项元素的数组与上一行前一项元素数组之和;否则与当前行前一项元素的数值相等
1 /* 2 ** "" a c d a b e f b c 3 ** "" 1 1 1 1 1 1 1 1 1 1 4 ** a 0 1 1 1 2 2 2 2 2 2 5 ** b 0 0 0 0 0 2 2 2 4 4 6 */ 7 public class Solution { 8 public int numDistinct(String s, String t) { 9 if (s.length() == 0) { 10 return t.length() == 0 ? 1 : 0; 11 } 12 if (t.length() == 0) { 13 return 1; 14 } 15 int[][] mem = new int[t.length() + 1][s.length() + 1]; 16 for (int j = 0; j <= s.length(); j++) { 17 mem[0][j] = 1; 18 } 19 for (int i = 0; i < t.length(); i++) { 20 for (int j = 0; j < s.length(); j++) { 21 if (s.charAt(j) == t.charAt(i)) { 22 mem[i + 1][j + 1] = mem[i][j] + mem[i + 1][j]; 23 } else { 24 mem[i + 1][j + 1] = mem[i + 1][j]; 25 } 26 } 27 } 28 return mem[t.length()][s.length()]; 29 } 30 }
118. Pascal's Triangle
思路:看答案,每次循环时,先添加了一个元素1,使list保持当前长度不变,然后更新list内的元素
1 /* * 2 * 1 3 * 1 1 4 * 1 2 1 5 * 1 3 3 1 6 *1 4 6 4 1 7 * */ 8 class Solution { 9 public List> generate(int numRows) { 10 List
> result = new ArrayList<>(); 11 List
list = new ArrayList<>(); 12 for (int i = 0; i < numRows; i++) { 13 list.add(0, 1); 14 for (int j = 1; j < list.size() - 1; j++) { 15 list.set(j, list.get(j) + list.get(j + 1)); 16 } 17 result.add(new ArrayList<>(list)); 18 } 19 return result; 20 } 21 }
注意:
1.list.add(0, 1)是插入语句,所有元素向后移动一位
2.记得添加到result里要new
119. Pascal's Triangle II
思路:和上道题目区别不大
1 class Solution { 2 public ListgetRow(int rowIndex) { 3 List res = new ArrayList<>(); 4 for (int i = 0; i <= rowIndex; i++) { 5 res.add(0, 1); 6 for (int j = 1; j < res.size() - 1; j++) { 7 res.set(j, res.get(j) + res.get(j + 1)); 8 } 9 } 10 return res; 11 } 12 }
121. Best Time to Buy and Sell Stock
思路:遍历数组,获取当前位置以前的最小值,用当前值减去这个最小值进行比较即可得到最大利润
1 class Solution { 2 public int maxProfit(int[] prices) { 3 int min = Integer.MAX_VALUE; 4 int max = 0; 5 for (int i = 0; i < prices.length; i++) { 6 min = Math.min(min, prices[i]); 7 max = Math.max(max, prices[i] - min); 8 } 9 return max; 10 } 11 }
122. Best Time to Buy and Sell Stock II
思路:当a<=b<=c<=d,则d - a = (d - c) + (c - b) + (b - a);当a<=b>=b`<=c<=d,则最大利润为(b - a) + (d - b`) = (b - a) + (d - c) + (c - b`)
1 class Solution { 2 public int maxProfit(int[] prices) { 3 int max = 0; 4 for (int i = 1; i < prices.length; i++) { 5 if (prices[i] > prices[i - 1]) { 6 max += prices[i] - prices[i - 1]; 7 } 8 } 9 return max; 10 } 11 }
125. Valid Palindrome
思路:两个指针,收尾遇到数字或者字母则开始比较,否则跳过
1 class Solution { 2 public boolean isPalindrome(String s) { 3 int start = 0; 4 int end = s.length() - 1; 5 while (start <= end) { 6 char head = s.charAt(start); 7 char tail = s.charAt(end); 8 if (!Character.isLetterOrDigit(head)) { 9 start++; 10 } else if (!Character.isLetterOrDigit(tail)) { 11 end--; 12 } else { 13 if (Character.toLowerCase(head) != Character.toLowerCase(tail)) { 14 return false; 15 } 16 start++; 17 end--; 18 } 19 } 20 return true; 21 } 22 }
136. Single Number
思路:由于数组中只有一个数字是单独的,其他的都是出现两次(偶数次就可以),则通过异或操作就可找到单独的数字
1 class Solution { 2 public int singleNumber(int[] nums) { 3 int target = 0; 4 for (int num : nums) { 5 target ^= num; 6 } 7 return target; 8 } 9 }
137. Single Number II
思路:由于整数有32位,因此建立一个32个元素的数组,用来存储整数中每一位中1的个数,这样就可以找到单一的元素
1 class Solution { 2 public int singleNumber(int[] nums) { 3 int[] array = new int[32]; 4 int res = 0; 5 for (int i = 0; i < 32; i++) { 6 for (int j = 0; j < nums.length; j++) { 7 array[i] += (nums[j] >> i) & 1; 8 } 9 res |= (array[i] % 3) << i; 10 } 11 return res; 12 } 13 }
141. Linked List Cycle
思路:快慢指针
1 /** 2 * Definition for singly-linked list. 3 * 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 public boolean hasCycle(ListNode head) { 14 if (head == null || head.next == null) { 15 return false; 16 } 17 ListNode fast = head.next; 18 ListNode slow = head; 19 while (fast != slow) { 20 if (fast == null || fast.next == null) { 21 return false; 22 } 23 fast = fast.next.next; 24 slow = slow.next; 25 } 26 return true; 27 } 28 }
155. Min Stack
思路:见注释
1 /** 使用两个栈来实现最小栈的操作 2 * minStack stack 3 * -3 4 * -3 0 5 * -2 -2 6 * push()操作:stack按照普通的栈处理,minStack只有在当前数字小于等于最小栈的栈顶时才加入 7 * pop()操作:此时的值就是stack栈顶的元素,但是要考虑minStack,当stack的栈顶元素与minStack的栈顶相同时,此时最小栈的栈顶也要pop()出来 8 */ 9 10 class MinStack { 11 12 /** initialize your data structure here. */ 13 Stackstack; 14 Stack minStack; 15 16 public MinStack() { 17 stack = new Stack<>(); 18 minStack = new Stack<>(); 19 } 20 21 public void push(int x) { 22 stack.push(x); 23 if (minStack.isEmpty()) { 24 minStack.push(x); 25 } else { 26 if (minStack.peek() >= x) { 27 minStack.push(x); 28 } 29 } 30 } 31 32 public void pop() { 33 if (stack.peek().equals(minStack.peek())) { 34 minStack.pop(); 35 } 36 stack.pop(); 37 } 38 39 public int top() { 40 return stack.peek(); 41 } 42 43 public int getMin() { 44 return minStack.peek(); 45 } 46 } 47 48 /** 49 * Your MinStack object will be instantiated and called as such: 50 * MinStack obj = new MinStack(); 51 * obj.push(x); 52 * obj.pop(); 53 * int param_3 = obj.top(); 54 * int param_4 = obj.getMin(); 55 */
160. 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 public ListNode getIntersectionNode(ListNode headA, ListNode headB) { 14 if (headA == null || headB == null) { 15 return null; 16 } 17 ListNode tailA = headA; 18 while (tailA.next != null) { 19 tailA = tailA.next; 20 } 21 tailA.next = headA; 22 // 这里必须使用一个方法,否则就会破坏原链表的结构,也不清楚原因 23 ListNode result = detectCycle(headB); 24 tailA.next = null; 25 return result; 26 } 27 private ListNode detectCycle(ListNode head) { 28 ListNode fast = head.next; 29 ListNode slow = head; 30 while (slow != fast) { 31 if (fast == null || fast.next == null) { 32 return null; 33 } 34 fast = fast.next.next; 35 slow = slow.next; 36 } 37 while (head != slow.next) { 38 head = head.next; 39 slow = slow.next; 40 } 41 return head; 42 } 43 }
第二种方法:看discuss
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 public ListNode getIntersectionNode(ListNode headA, ListNode headB) { 14 ListNode a = headA; 15 ListNode b = headB; 16 while (a != b) { 17 a = a == null ? headB : a.next; 18 b = b == null ? headA : b.next; 19 } 20 return a; 21 } 22 }
167. Two Sum II - Input array is sorted
思路:
第一种方法:采用hashMap
1 class Solution { 2 public int[] twoSum(int[] numbers, int target) { 3 HashMaphash = new HashMap<>(); 4 int[] res = new int[2]; 5 for (int i = 0; i < numbers.length; i++) { 6 if (hash.containsKey(numbers[i])) { 7 res[0] = hash.get(numbers[i]); 8 res[1] = i + 1; 9 } 10 hash.put(target - numbers[i], i + 1); 11 } 12 return res; 13 } 14 }
第二种方法:两个指针
1 class Solution { 2 public int[] twoSum(int[] numbers, int target) { 3 int[] res = new int[2]; 4 if (numbers == null || numbers.length == 0) { 5 return res; 6 } 7 int start = 0; 8 int end = numbers.length - 1; 9 while (start < end) { 10 int sum = numbers[start] + numbers[end]; 11 if (sum == target) { 12 res[0] = start + 1; 13 res[1] = end + 1; 14 return res; 15 } else if (sum > target) { 16 end--; 17 } else { 18 start++; 19 } 20 } 21 return res; 22 } 23 }
168. Excel Sheet Column Title
思路:只要注意要写成--n
1 class Solution { 2 public String convertToTitle(int n) { 3 return n == 0 ? "" : convertToTitle(--n / 26) + (char) ('A' + n % 26); 4 } 5 }
169. Majority Element
思路:投票算法(要求必须大于n/2,不能等于)
算法具体思路:假设在给定长度为n的数组,Majority Element出现的次数是k次,那么非Majority Element的出现次数就是n-k次,如果去掉这n-k个元素,那么剩下的就全部是Majority Element
我们采取遍历数组,当碰到两个不一样的数字时,我们将这两个数字同时丢弃,则两个元素中有可能一个为Majority Element,有可能两个都不是Majority Element。由于k大于n/2,所以在最差情况下(每次移除不同数字时都包含一个Majority Element),我们仍然能够保证最后得到的数字是Majority Element
1 class Solution { 2 public int majorityElement(int[] nums) { 3 int major = nums[0]; 4 int count = 1; 5 for (int i = 1; i < nums.length; i++) { 6 if (count == 0) { 7 major = nums[i]; 8 count++; 9 } else if (nums[i] == major) { 10 count++; 11 } else { 12 count--; 13 } 14 } 15 return major; 16 } 17 }
171. Excel Sheet Column Number
1 class Solution { 2 public int titleToNumber(String s) { 3 int len = s.length(); 4 int num = 0; 5 for (int i = 0; i < len; i++) { 6 num = num * 26 + s.charAt(i) - 'A' + 1; 7 } 8 return num; 9 } 10 }
172. Factorial Trailing Zeroes
思路:时间复杂度为o(logn),我们只需要考虑n!的因子即可,后缀0是由因子5与因子2相乘得到,经过列举我们知道2的个数总是多于5的个数,因此只需要找到质因子中所有5的个数,例如,7!有一个5,10!有两个5。除此之外,还有一件事情要考虑。诸如25,125之类的数字有不止一个5。例如,如果我们考虑28!,我们得到一个额外的5,并且0的总数变成了6。处理这个问题也很简单,首先对n÷5,移除所有的单个5,然后÷25,移除额外的5,以此类推。
1 class Solution { 2 public int trailingZeroes(int n) { 3 return n == 0 ? 0 : n / 5 + trailingZeroes(n / 5); 4 } 5 }
189. Rotate Array
思路:三次翻转即可实现,不过翻转方法有许多
1 class Solution { 2 public void rotate(int[] nums, int k) { 3 k %= nums.length; 4 reverse(nums, 0, nums.length - k - 1); 5 reverse(nums, nums.length - k, nums.length - 1); 6 reverse(nums, 0, nums.length - 1); 7 } 8 private void reverse(int[] nums, int start, int end) { 9 while (start < end) { 10 int temp = nums[start]; 11 nums[start] = nums[end]; 12 nums[end] = temp; 13 start++; 14 end--; 15 } 16 } 17 }
1 class Solution { 2 public void rotate(int[] nums, int k) { 3 k %= nums.length; 4 reverse(nums, 0, nums.length - 1); 5 reverse(nums, 0, k - 1); 6 reverse(nums, k, nums.length - 1); 7 } 8 private void reverse(int[] nums, int start, int end) { 9 while (start < end) { 10 int temp = nums[start]; 11 nums[start] = nums[end]; 12 nums[end] = temp; 13 start++; 14 end--; 15 } 16 } 17 }
190. Reverse Bits
思路:技巧性较强
1 public class Solution { 2 // you need treat n as an unsigned value 3 /** 4 * abcdefgh -> efghabcd -> ghefcdab -> hgfedcba 5 **/ 6 public int reverseBits(int n) { 7 n = (n >>> 16) | (n << 16); 8 n = ((n & 0xff00ff00) >>> 8) | ((n & 0x00ff00ff) << 8); 9 n = ((n & 0xf0f0f0f0) >>> 4) | ((n & 0x0f0f0f0f) << 4); 10 n = ((n & 0xcccccccc) >>> 2) | ((n & 0x33333333) << 2); 11 n = ((n & 0xaaaaaaaa) >>> 1) | ((n & 0x55555555) << 1); 12 return n; 13 } 14 }
1 public class Solution { 2 // you need treat n as an unsigned value 3 public int reverseBits(int n) { 4 int result = 0; 5 for (int i = 0; i < 32; i++) { 6 result += n & 1; 7 n >>>= 1; 8 if (i != 31) { 9 result <<= 1; 10 } 11 } 12 return result; 13 } 14 }
198. House Robber
思路:DP问题,例如,数组元素为[1, 2, 3, 4, 5],此时索引为4的最大值是由索引为3位置的最大值以及索引为2的最大值加目前元素的数字相比较得到,所以求解时采用相反的方向即可。
1 class Solution { 2 public int rob(int[] nums) { 3 // 索引为偶数的目前最大数值 4 int a = 0; 5 // 索引为奇数的目前最大数值 6 int b = 0; 7 for (int i = 0; i < nums.length; i++) { 8 if (i % 2 == 0) { 9 a = Math.max(a + nums[i], b); 10 } else { 11 b = Math.max(a, b + nums[i]); 12 } 13 } 14 return Math.max(a, b); 15 } 16 }
202. Happy Number
思路:
第一种方法:采用HashSet,将每次生成的数存在hash表中,如果hash表存在得到的值,说明不是快乐数;循环退出条件,得到的值为1
1 class Solution { 2 public boolean isHappy(int n) { 3 HashSethash = new HashSet<>(); 4 while (n != 1) { 5 if (hash.contains(n)) { 6 return false; 7 } 8 hash.add(n); 9 n = getNextHappy(n); 10 } 11 return true; 12 } 13 private int getNextHappy(int n) { 14 int sum = 0; 15 while (n != 0) { 16 sum += Math.pow(n % 10, 2); 17 n /= 10; 18 } 19 return sum; 20 } 21 }
第二种方法:采用快慢指针
1 class Solution { 2 public boolean isHappy(int n) { 3 int fast = n; 4 int slow = n; 5 do { 6 slow = getNextHappy(slow); 7 fast = getNextHappy(fast); 8 fast = getNextHappy(fast); 9 } while (fast != slow); 10 if (slow == 1) { 11 return true; 12 } 13 return false; 14 } 15 private int getNextHappy(int n) { 16 int sum = 0; 17 while (n != 0) { 18 sum += Math.pow(n % 10, 2); 19 n = n / 10; 20 } 21 return sum; 22 } 23 }
203. Remove Linked List Elements
思路:比较简单的链表相关题目
1 /** 2 * Definition for singly-linked list. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { val = x; } 7 * } 8 */ 9 class Solution { 10 public ListNode removeElements(ListNode head, int val) { 11 ListNode dummy = new ListNode(0); 12 dummy.next = head; 13 head = dummy; 14 while (head.next != null) { 15 if (head.next.val == val) { 16 head.next = head.next.next; 17 } else { 18 head = head.next; 19 } 20 } 21 return dummy.next; 22 } 23 }
204. Count Primes
思路:简单地找素数的个数
1 class Solution { 2 public int countPrimes(int n) { 3 boolean[] notPrimes = new boolean[n]; 4 int count = 0; 5 for (int i = 2; i < n; i++) { 6 if (notPrimes[i] == false) { 7 count++; 8 for (int j = 2; i * j < n; j++) { 9 notPrimes[i * j] = true; 10 } 11 } 12 } 13 return count; 14 } 15 }
205. Isomorphic Strings
思路:由于ASCII码有256个,因此采用数组来代替,通过字符串的索引值加1(防止索引为0)来代替对应ASCII码对应的数值即可
1 class Solution { 2 public boolean isIsomorphic(String s, String t) { 3 if (s.length() != t.length()) { 4 return false; 5 } 6 int[] hash1 = new int[256]; 7 int[] hash2 = new int[256]; 8 for (int i = 0; i < s.length(); i++) { 9 if (hash1[s.charAt(i)] != hash2[t.charAt(i)]) { 10 return false; 11 } 12 hash1[s.charAt(i)] = i + 2; 13 hash2[t.charAt(i)] = i + 2; 14 } 15 return true; 16 } 17 }
206. Reverse Linked List
思路:要记住该过程,链表比较基础的题目
1 /** 2 * Definition for singly-linked list. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { val = x; } 7 * } 8 */ 9 class Solution { 10 public ListNode reverseList(ListNode head) { 11 ListNode prev = null; 12 while (head != null) { 13 ListNode temp = head.next; 14 head.next = prev; 15 prev = head; 16 head = temp; 17 } 18 return prev; 19 } 20 }
215. Kth Largest Element in an Array
思路:
方法一:采用快排的思想,选出数组中任意元素,将所有比它大的放在其前,然后分成三部分分别判断
1 class Solution { 2 public int findKthLargest(int[] nums, int k) { 3 if (nums == null || nums.length == 0) { 4 return -1; 5 } 6 return quickSelect(nums, 0, nums.length - 1, k - 1); 7 } 8 private int quickSelect(int[] nums, int start, int end, int k) { 9 if (start >= end) { 10 return nums[start]; 11 } 12 int left = start; 13 int right = end; 14 int pivot = nums[(start + end) / 2]; 15 while (left <= right) { 16 while (left <= right && nums[left] > pivot) { 17 left++; 18 } 19 while (left <= right && nums[right] < pivot) { 20 right--; 21 } 22 if (left <= right) { 23 int temp = nums[left]; 24 nums[left] = nums[right]; 25 nums[right] = temp; 26 left++; 27 right--; 28 } 29 } 30 if (right >= k && right >= start) { 31 return quickSelect(nums, start, right, k); 32 } else if (left <= k && left <= end) { 33 return quickSelect(nums, left, end, k); 34 } 35 return nums[k]; 36 } 37 }
方法二:从剩下最大的一堆数中找最小值,借助最小堆
1 class Solution { 2 public int findKthLargest(int[] nums, int k) { 3 if (nums == null || nums.length == 0) { 4 return -1; 5 } 6 QueueminHeap = new PriorityQueue<>(); 7 for (int num : nums) { 8 minHeap.offer(num); 9 if (minHeap.size() > k) { 10 minHeap.poll(); 11 } 12 } 13 return minHeap.poll(); 14 } 15 }
217. Contains Duplicate
思路:
第一种方法:采用HashSet
1 // time:o(n) 2 // memory:o(n) 3 class Solution { 4 public boolean containsDuplicate(int[] nums) { 5 HashSethash = new HashSet<>(); 6 for (int i = 0; i < nums.length; i++) { 7 if (hash.contains(nums[i])) { 8 return true; 9 } 10 hash.add(nums[i]); 11 } 12 return false; 13 } 14 }
第二种方法:排序后再找重复元素
1 /** 2 * time: o(nlgn) 3 * memory: o(1) 4 **/ 5 class Solution { 6 public boolean containsDuplicate(int[] nums) { 7 if (nums == null || nums.length == 0) { 8 return false; 9 } 10 Arrays.sort(nums); 11 for(int i = 1; i < nums.length; i++) { 12 if (nums[i] == nums[i - 1]) { 13 return true; 14 } 15 } 16 return false; 17 } 18 }
219. Contains Duplicate II
第一种方法:自己想的,比较复杂,采用了HashMap
1 class Solution { 2 public boolean containsNearbyDuplicate(int[] nums, int k) { 3 if (nums.length == 0 || nums == null) { 4 return false; 5 } 6 HashMaphash = new HashMap<>(); 7 for (int i = 0; i < nums.length; i++) { 8 if (hash.containsKey(nums[i]) && Math.abs(i - hash.get(nums[i])) <= k) { 9 return true; 10 } else { 11 hash.put(nums[i], i); 12 } 13 } 14 return false; 15 } 16 }
第二种方法:看答案,相对比较简单
1 class Solution { 2 public boolean containsNearbyDuplicate(int[] nums, int k) { 3 HashSethash = new HashSet<>(); 4 for (int i = 0; i < nums.length; i++) { 5 if (i > k) { 6 hash.remove(nums[i - k - 1]); 7 } 8 // 巧妙 9 if (!hash.add(nums[i])) { 10 return true; 11 } 12 } 13 return false; 14 } 15 }
225. Implement Stack using Queues
思路:
第一种方法:采用一个队列实现栈,每次加入队列是,都要将顺序进行翻转,这样就保证了先进后出
1 class MyStack { 2 3 /** Initialize your data structure here. */ 4 private Queuequeue; 5 6 public MyStack() { 7 queue = new LinkedList<>(); 8 } 9 10 /** Push element x onto stack. */ 11 public void push(int x) { 12 queue.offer(x); 13 for (int i = 0; i < queue.size() - 1; i++) { 14 queue.offer(queue.poll()); 15 } 16 } 17 18 /** Removes the element on top of the stack and returns that element. */ 19 public int pop() { 20 return queue.poll(); 21 } 22 23 /** Get the top element. */ 24 public int top() { 25 return queue.peek(); 26 } 27 28 /** Returns whether the stack is empty. */ 29 public boolean empty() { 30 return queue.isEmpty(); 31 } 32 } 33 34 /** 35 * Your MyStack object will be instantiated and called as such: 36 * MyStack obj = new MyStack(); 37 * obj.push(x); 38 * int param_2 = obj.pop(); 39 * int param_3 = obj.top(); 40 * boolean param_4 = obj.empty(); 41 */
第二种方法:用两个队列实现栈
1 class MyStack { 2 3 /** Initialize your data structure here. */ 4 private Queuequeue1; 5 private Queue queue2; 6 7 public MyStack() { 8 queue1 = new LinkedList<>(); 9 queue2 = new LinkedList<>(); 10 } 11 12 /** Push element x onto stack. */ 13 public void push(int x) { 14 queue1.offer(x); 15 } 16 17 /** Removes the element on top of the stack and returns that element. */ 18 public int pop() { 19 queue1ToQueue2(); 20 int num = queue1.poll(); 21 swapQueue(); 22 return num; 23 } 24 25 /** Get the top element. */ 26 public int top() { 27 queue1ToQueue2(); 28 int num = queue1.poll(); 29 swapQueue(); 30 queue1.offer(num); 31 return num; 32 } 33 34 /** Returns whether the stack is empty. */ 35 public boolean empty() { 36 return queue1.isEmpty(); 37 } 38 39 private void queue1ToQueue2() { 40 while (queue1.size() != 1) { 41 queue2.offer(queue1.poll()); 42 } 43 } 44 45 private void swapQueue() { 46 Queue temp = queue1; 47 queue1 = queue2; 48 queue2 = temp; 49 } 50 } 51 52 /** 53 * Your MyStack object will be instantiated and called as such: 54 * MyStack obj = new MyStack(); 55 * obj.push(x); 56 * int param_2 = obj.pop(); 57 * int param_3 = obj.top(); 58 * boolean param_4 = obj.empty(); 59 */
226. Invert Binary Tree
思路:
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public TreeNode invertTree(TreeNode root) { 12 if (root == null) { 13 return null; 14 } 15 TreeNode temp = root.left; 16 root.left = root.right; 17 root.right = temp; 18 invertTree(root.left); 19 invertTree(root.right); 20 return root; 21 } 22 }
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public TreeNode invertTree(TreeNode root) { 12 if (root == null) { 13 return null; 14 } 15 TreeNode temp = root.left; 16 root.left = invertTree(root.right); 17 root.right = invertTree(temp); 18 return root; 19 } 20 }
229. Majority Element II
思路:具体方法见文档(http://goo.gl/64Nams),由于要求数字出现次数大于n/3,故最多两个数字出现在结果中,具体步骤如下:
- 初始化两个数字,并赋予它们的投票次数为0
- 每当出现两个数字的某一个时,将其次数加1;如果两个数字都没出现,则次数减1
- 当次数为0时,将需要的投票数字变为当前数字,在剩下的数组中进行投票
- 最后选出的两个数字再进行检验
1 public class Solution { 2 public ListmajorityElement(int[] nums) { 3 List result = new ArrayList<>(); 4 if (nums.length == 0 || nums == null) { 5 return result; 6 } 7 int len = nums.length; 8 int standard = len / 3; 9 10 int candidate1 = 0; 11 int candidate2 = 1; 12 int count1 = 0; 13 int count2 = 0; 14 for (int i = 0; i < len; i++) { 15 if (candidate1 == nums[i]) { 16 count1++; 17 } else if (candidate2 == nums[i]) { 18 count2++; 19 } else if (count1 == 0) { 20 candidate1 = nums[i]; 21 count1 = 1; 22 } else if (count2 == 0) { 23 candidate2 = nums[i]; 24 count2 = 1; 25 } else { 26 count1--; 27 count2--; 28 } 29 } 30 count1 = 0; 31 count2 = 0; 32 for (int i = 0; i < len; i++) { 33 if (nums[i] == candidate1) { 34 count1++; 35 } else if (nums[i] == candidate2) { 36 count2++; 37 } 38 } 39 40 if (count1 > standard) { 41 result.add(candidate1); 42 } 43 if (count2 > standard) { 44 result.add(candidate2); 45 } 46 return result; 47 } 48 }
注意:
- count == 0 是用来判断target的当前存活量,在判断这一步之前,我们必须确保数组中当前数字不等于两个target中的任意一个。否则,当count0 != 0 && count1 == 0 && nums[i] == target0,此时错误的将nums[i] 赋值给 target1
- 当数组所有的数字全部相等时,我们两个候选数字中,有一个数字永远不会被重新赋值,即有一个数字将我们赋给的初值保持到了最后,因此当我们将两个数字都初始化为0时,数组全为0时将会发生错误,因此我们将其中一个赋初值为1
231. Power of Two
思路:由于2的幂次数字只要最高位为1,因此采用位运算,即n & (n - 1)即可得到答案
1 class Solution { 2 public boolean isPowerOfTwo(int n) { 3 if (n <= 0) { 4 return false; 5 } 6 return (n & (n - 1)) == 0; 7 } 8 }
232. Implement Queue using Stacks
思路:简单
1 class MyQueue { 2 3 Stackstack1; 4 Stack stack2; 5 /** Initialize your data structure here. */ 6 public MyQueue() { 7 stack1 = new Stack<>(); 8 stack2 = new Stack<>(); 9 } 10 11 /** Push element x to the back of queue. */ 12 public void push(int x) { 13 stack1.push(x); 14 } 15 16 /** Removes the element from in front of queue and returns that element. */ 17 public int pop() { 18 if (stack2.isEmpty()) { 19 stack1ToStack2(); 20 } 21 return stack2.pop(); 22 } 23 24 /** Get the front element. */ 25 public int peek() { 26 if (stack2.isEmpty()) { 27 stack1ToStack2(); 28 } 29 return stack2.peek(); 30 } 31 32 /** Returns whether the queue is empty. */ 33 public boolean empty() { 34 return stack1.isEmpty() && stack2.isEmpty(); 35 } 36 37 private void stack1ToStack2() { 38 while (!stack1.isEmpty()) { 39 stack2.push(stack1.pop()); 40 } 41 } 42 } 43 44 /** 45 * Your MyQueue object will be instantiated and called as such: 46 * MyQueue obj = new MyQueue(); 47 * obj.push(x); 48 * int param_2 = obj.pop(); 49 * int param_3 = obj.peek(); 50 * boolean param_4 = obj.empty(); 51 */
233. Number of Digit One
1 class Solution { 2 public int countDigitOne(int n) { 3 int ones = 0; 4 for (long m = 1; m <= n; m *= 10) { 5 long a = n / m; 6 long b = n % m; 7 /** 8 * 比如32410 92,此时a=32410, b=92;对于等式前半部分,由于(a+8) / 10 = 3241,后半部分为零 9 * 比如32411 92, 此时a=32411,b=92;对于等式前半部分,由于(a+8) / 10 = 3241,后半部分=92+1 10 * 比如32415 92,此时a=32415,b=92;对于等式前半部分,由于进位(a+8) / 10 = 3242(对于>=2),后半部分为零 11 */ 12 ones += (a + 8) / 10 * m + (a % 10 == 1 ? b + 1 : 0); 13 } 14 return ones; 15 } 16 }
234. Palindrome Linked List
思路:先找到中间的节点,将middle.next以后的节点进行翻转,再比较两节链表即可
1 /** 2 * Definition for singly-linked list. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { val = x; } 7 * } 8 */ 9 class Solution { 10 public boolean isPalindrome(ListNode head) { 11 if (head == null) { 12 return true; 13 } 14 ListNode mid = findMid(head); 15 mid.next = reverse(mid.next); 16 17 ListNode p1 = head; 18 ListNode p2 = mid.next; 19 while (p1 != null && p2 != null && p1.val == p2.val) { 20 p1 = p1.next; 21 p2 = p2.next; 22 } 23 return p2 == null; 24 } 25 private ListNode findMid(ListNode head) { 26 ListNode slow = head; 27 ListNode fast = head.next; 28 while (fast != null && fast.next != null) { 29 slow = slow.next; 30 fast = fast.next.next; 31 } 32 return slow; 33 } 34 35 private ListNode reverse(ListNode head) { 36 ListNode prev = null; 37 while (head != null) { 38 ListNode temp = head.next; 39 head.next = prev; 40 prev = head; 41 head = temp; 42 } 43 return prev; 44 } 45 }
注意:
1. 最后要判断为p2 == null ,当只有一个节点时,这样就可得到正确结果
235. Lowest Common Ancestor of a Binary Search Tree
思路:
第一种方法:求公共子节点的典型方法,有三种情况:再root节点的两侧;全部在左子节点;全部在右子节点
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { 12 if (root == null || root == p || root == q) { 13 return root; 14 } 15 TreeNode left = lowestCommonAncestor(root.left, p, q); 16 TreeNode right = lowestCommonAncestor(root.right, p, q); 17 if (left != null && right != null) { 18 return root; 19 } 20 if (left != null) { 21 return left; 22 } 23 if (right != null) { 24 return right; 25 } 26 return null; 27 } 28 }
第二种方法:由于该树为BST,因此可以通过节点值相减得到p、q的所在位置
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { 12 if (root == null) { 13 return null; 14 } 15 while ((root.val - p.val) * (root.val - q.val) > 0) { 16 root = root.val > p.val ? root.left : root.right; 17 } 18 return root; 19 } 20 }
237. Delete Node in a Linked List
思路:简单的题目
1 /** 2 * Definition for singly-linked list. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { val = x; } 7 * } 8 */ 9 class Solution { 10 public void deleteNode(ListNode node) { 11 node.val = node.next.val; 12 node.next = node.next.next; 13 } 14 }
242. Valid Anagram
思路:比较简单,常见的思路
1 class Solution { 2 public boolean isAnagram(String s, String t) { 3 int[] count = new int[26]; 4 for (int i = 0; i < s.length(); i++) { 5 count[s.charAt(i) - 'a']++; 6 } 7 for (int i = 0; i < t.length(); i++) { 8 count[t.charAt(i) - 'a']--; 9 } 10 for (int i = 0; i < 26; i++) { 11 if (count[i] != 0) { 12 return false; 13 } 14 } 15 return true; 16 } 17 }
257. Binary Tree Paths
第一种方法:采用分治算法,左右子树分别开工
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public ListbinaryTreePaths(TreeNode root) { 12 List res = new ArrayList<>(); 13 if (root == null) { 14 return res; 15 } 16 List leftPaths = binaryTreePaths(root.left); 17 List rightPaths = binaryTreePaths(root.right); 18 for (String left : leftPaths) { 19 res.add(root.val + "->" + left); 20 } 21 for (String right : rightPaths) { 22 res.add(root.val + "->" + right); 23 } 24 // leaf 25 if (res.size() == 0) { 26 res.add(root.val + ""); 27 } 28 return res; 29 } 30 }
第二种方法:采用DFS
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public ListbinaryTreePaths(TreeNode root) { 12 List res = new ArrayList<>(); 13 if (root == null) { 14 return res; 15 } 16 helper(root, String.valueOf(root.val), res); 17 return res; 18 } 19 private void helper(TreeNode root, String path, List res) { 20 if (root == null) { 21 return; 22 } 23 if (root.left == null && root.right == null) { 24 res.add(path); 25 } 26 if (root.left != null) { 27 helper(root.left, path + "->" + root.left.val, res); 28 } 29 if (root.right != null) { 30 helper(root.right, path + "->" + root.right.val, res); 31 } 32 } 33 }
258. Add Digits
思路:递归的思想
1 class Solution { 2 public int addDigits(int num) { 3 if (num < 10) { 4 return num; 5 } 6 int sum = 0; 7 while (num != 0) { 8 sum += num % 10; 9 num /= 10; 10 } 11 return addDigits(sum); 12 } 13 }
263. Ugly Number
思路:
1 class Solution { 2 public boolean isUgly(int num) { 3 if (num < 0) { 4 return false; 5 } 6 if (num == 1) { 7 return true; 8 } 9 while (num >= 2 && num % 2 == 0) { 10 num /= 2; 11 } 12 while (num >= 3 && num % 3 == 0) { 13 num /= 3; 14 } 15 while (num >= 5 && num % 5 == 0) { 16 num /= 5; 17 } 18 return num == 1; 19 } 20 }
268. Missing Number
第一种方法:采用位运算,两个相同的数字异或等于0,最后找到的即为缺失的数字
1 class Solution { 2 public int missingNumber(int[] nums) { 3 int res = nums.length; 4 for (int i = 0; i < nums.length; i++) { 5 res ^= i; 6 res ^= nums[i]; 7 } 8 return res; 9 } 10 }
第二种方法:二分法
1 class Solution { 2 public int missingNumber(int[] nums) { 3 Arrays.sort(nums); 4 int start = 0; 5 int end = nums.length; 6 while (start + 1 < end) { 7 int mid = start + (end - start) / 2; 8 if (nums[mid] > mid) { 9 end = mid; 10 } else { 11 start = mid; 12 } 13 } 14 if (nums[start] == start) { 15 return end; 16 } else { 17 return start; 18 } 19 } 20 }
278. First Bad Version
思路:简单的二分查找
1 /* The isBadVersion API is defined in the parent class VersionControl. 2 boolean isBadVersion(int version); */ 3 4 public class Solution extends VersionControl { 5 public int firstBadVersion(int n) { 6 int start = 1; 7 int end = n; 8 while (start + 1 < end) { 9 int mid = start + (end - start) / 2; 10 if (isBadVersion(mid)) { 11 end = mid; 12 } else { 13 start = mid; 14 } 15 } 16 if (isBadVersion(start)) { 17 return start; 18 } 19 return end; 20 } 21 }
283. Move Zeroes
思路:也可以直接用两根指针,一根指针表示交换不为零的数字,另外一个遍历数组
1 class Solution { 2 public void moveZeroes(int[] nums) { 3 int len = 0; 4 for (int i = 0; i < nums.length; i++) { 5 if (nums[i] != 0) { 6 nums[len++] = nums[i]; 7 } 8 } 9 for (int i = len; i < nums.length; i++) { 10 nums[i] = 0; 11 } 12 } 13 }
290. Word Pattern
思路:采用HashMap,索引是字符串以及字符,value是对应在字符串的位置,由于put方法,一旦替换其value,就会返回旧的value值,这样就可以比较
1 class Solution { 2 public boolean wordPattern(String pattern, String str) { 3 String[] words = str.split(" "); 4 if (pattern.length() != words.length) { 5 return false; 6 } 7 HashMap index = new HashMap(); 8 for (int i = 0; i < words.length; i++) { 9 if (!Objects.equals(index.put(pattern.charAt(i), i), index.put(words[i], i))) { 10 return false; 11 } 12 } 13 return true; 14 } 15 }
注意:
1. 采用Objects.equals()进行比较
292. Nim Game
思路:比较巧妙
1 class Solution { 2 public boolean canWinNim(int n) { 3 return n % 4 != 0; 4 } 5 }
300. Longest Increasing Subsequence
思路:
方法一:动态规划问题,使用一个cnt数组记录当前位置最大的LIS的长度,第一层遍历数组,第二层递归以第一层的为截止进行搜索
1 // time:o(n^2) 2 class Solution { 3 public int lengthOfLIS(int[] nums) { 4 if (nums == null || nums.length == 0) { 5 return 0; 6 } 7 int[] len = new int[nums.length]; 8 int max = 0; 9 for (int i = 0; i < nums.length; i++) { 10 len[i] = 1; 11 for (int j = 0; j < i; j++) { 12 if (nums[i] > nums[j]) { 13 // 更新当前i的LIS的长度 14 /*只有索引i对应的数字大于当前j对应的数字时,更新索引i对应的当前LIS的最大长度*/ 15 len[i] = (len[i] > len[j] + 1) ? len[i] : len[j] + 1; 16 } 17 } 18 if (max < len[i]) { 19 max = len[i]; 20 } 21 } 22 return max; 23 } 24 }
方法二:结合二分法,时间复杂度降低
303. Range Sum Query - Immutable
思路:设计数据结构,简单
1 class NumArray { 2 3 int[] nums; 4 public NumArray(int[] nums) { 5 for (int i = 1; i < nums.length; i++) { 6 nums[i] += nums[i - 1]; 7 } 8 this.nums = nums; 9 } 10 11 public int sumRange(int i, int j) { 12 if (i == 0) { 13 return nums[j]; 14 } 15 return nums[j] - nums[i - 1]; 16 } 17 } 18 19 /** 20 * Your NumArray object will be instantiated and called as such: 21 * NumArray obj = new NumArray(nums); 22 * int param_1 = obj.sumRange(i,j); 23 */
318. Maximum Product of Word Lengths
思路:将单词中每个字母相对于a的位置记录在数字中(通过或运算和位移运算实现),将所有字母得到的数字记录在数组中;再次通过与运算数组中的数字即可得到是否有重复字母
1 class Solution { 2 public int maxProduct(String[] words) { 3 if (words == null || words.length < 2) { 4 return 0; 5 } 6 int len = words.length; 7 int[] values = new int[len]; 8 for (int i = 0; i < len; i++) { 9 for (int j = 0; j < words[i].length(); j++) { 10 values[i] |= 1 << (words[i].charAt(j) - 'a'); 11 } 12 } 13 14 int maxProduct = 0; 15 for (int i = 0; i < len; i++) { 16 for (int j = i + 1; j < len; j++) { 17 if ((values[i] & values[j]) == 0) { 18 maxProduct = Math.max(words[i].length() * words[j].length(), maxProduct); 19 } 20 } 21 } 22 return maxProduct; 23 } 24 }
322. Coin Change
思路:比较经典的动态规划问题
- 创建数组res,索引表示硬币的面额,数值表示所需的最小硬币数,注意res[0],不要忘记
- 初始化res数组,res[0]不需要初始化,其余初始化为int类型的最大值减1,为了防止特殊情况,加1导致溢出
- res[j] = Math.min(res[j], res[j - coins[i]]) 其中coins[j]为第j个硬币,而i - coins[j]为钱数i减去其中一个硬币的值,剩余的钱数在res数组中找到值,然后加1和当前res数组中的值做比较,取较小的那个更新res数组
1 class Solution { 2 public int coinChange(int[] coins, int amount) { 3 int[] res = new int[amount + 1]; 4 for (int i = 1; i < res.length; i++) { 5 res[i] = Integer.MAX_VALUE - 1; 6 } 7 for (int i = 0; i < coins.length; i++) { 8 for (int j = coins[i]; j < res.length; j++) { 9 res[j] = Math.min(res[j], res[j - coins[i]] + 1); 10 } 11 } 12 if (res[amount] == Integer.MAX_VALUE - 1) { 13 return -1; 14 } 15 return res[amount]; 16 } 17 }
注意:
1. 初始化是res[0] = 0, 而且数组要最大值减1
2. 最后要做出判断,可能不存在
344. Reverse String
思路:翻转字符串
1 class Solution { 2 public String reverseString(String s) { 3 char[] c = s.toCharArray(); 4 for (int i = 0, j = c.length - 1; i < j; i++, j--) { 5 char temp = c[i]; 6 c[i] = c[j]; 7 c[j] = temp; 8 } 9 return new String(c); 10 } 11 }
345. Reverse Vowels of a String
思路:查看字符串中是否包含元音,可以采用hashSet,节省时间
1 class Solution { 2 public String reverseVowels(String s) { 3 if (s.length() == 0 || s == null) { 4 return s; 5 } 6 String vowels = "aeiouAEIOU"; 7 char[] chars = s.toCharArray(); 8 int start = 0; 9 int end = s.length() - 1; 10 while (start < end) { 11 while (start < end && !vowels.contains(chars[start] + "")) { 12 start++; 13 } 14 while (start < end && !vowels.contains(chars[end] + "")) { 15 end--; 16 } 17 18 char temp = chars[start]; 19 chars[start] = chars[end]; 20 chars[end] = temp; 21 22 start++; 23 end--; 24 } 25 return new String(chars); 26 } 27 }
349. Intersection of Two Arrays
第一种方法:hashSet,time:o(n)
1 class Solution { 2 public int[] intersection(int[] nums1, int[] nums2) { 3 HashSethash = new HashSet<>(); 4 HashSet set = new HashSet<>(); 5 for (int num : nums1) { 6 hash.add(num); 7 } 8 for (int num : nums2) { 9 if (hash.contains(num)) { 10 set.add(num); 11 } 12 } 13 int[] res = new int[set.size()]; 14 int i = 0; 15 for (int num : set) { 16 res[i++] = num; 17 } 18 return res; 19 } 20 }
第二种方法:两根指针,time:o(nlogn)
1 class Solution { 2 public int[] intersection(int[] nums1, int[] nums2) { 3 HashSethash = new HashSet<>(); 4 Arrays.sort(nums1); 5 Arrays.sort(nums2); 6 int i = 0; 7 int j = 0; 8 while (i < nums1.length && j < nums2.length) { 9 if (nums1[i] > nums2[j]) { 10 j++; 11 } else if (nums1[i] < nums2[j]) { 12 i++; 13 } else { 14 hash.add(nums1[i]); 15 i++; 16 j++; 17 } 18 } 19 int[] res = new int[hash.size()]; 20 int pos = 0; 21 for (int num : hash) { 22 res[pos++] = num; 23 } 24 return res; 25 } 26 }
第三种方法:二分法,time:o(nlogn)
1 class Solution { 2 public int[] intersection(int[] nums1, int[] nums2) { 3 HashSethash = new HashSet<>(); 4 Arrays.sort(nums2); 5 for (int num : nums1) { 6 if (binarySearch(nums2, num)) { 7 hash.add(num); 8 } 9 } 10 int[] res = new int[hash.size()]; 11 int i = 0; 12 for (int num : hash) { 13 res[i++] = num; 14 } 15 return res; 16 } 17 private boolean binarySearch(int[] nums, int num) { 18 if (nums == null || nums.length == 0) { 19 return false; 20 } 21 int start = 0; 22 int end = nums.length - 1; 23 while (start + 1 < end) { 24 int mid = start + (end - start) / 2; 25 if (nums[mid] == num) { 26 return true; 27 } else if (nums[mid] > num) { 28 end = mid; 29 } else { 30 start = mid; 31 } 32 } 33 if (nums[start] == num || nums[end] == num) { 34 return true; 35 } 36 return false; 37 } 38 }
350. Intersection of Two Arrays II
方法一:采用hashMap
1 class Solution { 2 public int[] intersect(int[] nums1, int[] nums2) { 3 HashMaphash = new HashMap<>(); 4 ArrayList list = new ArrayList<>(); 5 for (int num : nums1) { 6 if (hash.containsKey(num)) { 7 hash.put(num, hash.get(num) + 1); 8 } else { 9 hash.put(num, 1); 10 } 11 } 12 for (int num : nums2) { 13 if (hash.containsKey(num) && hash.get(num) > 0) { 14 list.add(num); 15 hash.put(num, hash.get(num) - 1); 16 } 17 } 18 int[] res = new int[list.size()]; 19 int i = 0; 20 for (int num : list) { 21 res[i++] = num; 22 } 23 return res; 24 } 25 }
方法二:采用两根指针
1 class Solution { 2 public int[] intersect(int[] nums1, int[] nums2) { 3 ArrayListlist = new ArrayList<>(); 4 Arrays.sort(nums1); 5 Arrays.sort(nums2); 6 int i = 0; 7 int j = 0; 8 while (i < nums1.length && j < nums2.length) { 9 if (nums1[i] < nums2[j]) { 10 i++; 11 } else if (nums1[i] > nums2[j]) { 12 j++; 13 } else { 14 list.add(nums1[i]); 15 i++; 16 j++; 17 } 18 } 19 int[] res = new int[list.size()]; 20 int pos = 0; 21 for (int num : list) { 22 res[pos++] = num; 23 } 24 return res; 25 } 26 }
350. Intersection of Two Arrays II
方法一:采用hashMap
1 class Solution { 2 public int[] intersect(int[] nums1, int[] nums2) { 3 HashMaphash = new HashMap<>(); 4 ArrayList list = new ArrayList<>(); 5 for (int num : nums1) { 6 if (hash.containsKey(num)) { 7 hash.put(num, hash.get(num) + 1); 8 } else { 9 hash.put(num, 1); 10 } 11 } 12 for (int num : nums2) { 13 if (hash.containsKey(num) && hash.get(num) > 0) { 14 list.add(num); 15 hash.put(num, hash.get(num) - 1); 16 } 17 } 18 int[] res = new int[list.size()]; 19 int i = 0; 20 for (int num : list) { 21 res[i++] = num; 22 } 23 return res; 24 } 25 }
方法二:两根指针
1 class Solution { 2 public int[] intersect(int[] nums1, int[] nums2) { 3 ArrayListlist = new ArrayList<>(); 4 Arrays.sort(nums1); 5 Arrays.sort(nums2); 6 int i = 0; 7 int j = 0; 8 while (i < nums1.length && j < nums2.length) { 9 if (nums1[i] < nums2[j]) { 10 i++; 11 } else if (nums1[i] > nums2[j]) { 12 j++; 13 } else { 14 list.add(nums1[i]); 15 i++; 16 j++; 17 } 18 } 19 int[] res = new int[list.size()]; 20 int pos = 0; 21 for (int num : list) { 22 res[pos++] = num; 23 } 24 return res; 25 } 26 }
363. Max Sum of Rectangle No Larger Than K
思路:
- 将二维数组转换为一维数组求解,一维数组的求解方法见Maximum Sum Rectangular Submatrix in Matrix dynamic programming/2D kadane,比较简单;
- 转换为一维数组后,即变成求解数组内任意子数组的和最接近k,这个也可见max subarray sum no more than k,这个方法即求解当前位置到数组开始位置的和,与k的差最大的值pre,得到后即可求出此时的最接近k的和,即将curSum - pre即可得到最大的和maxSum;
- 第一种方法采用了TreeSet提供的ceiling( )方法,第二种方法是完整的思路
1 public class Solution { 2 public int maxSumSubmatrix(int[][] matrix, int k) { 3 int len = matrix[0].length; 4 int dep = matrix.length; 5 int maxSum = Integer.MIN_VALUE; 6 for (int i = 0; i < len; i++) { 7 int[] sums = new int[dep]; 8 for (int j = i; j < len; j++) { 9 for (int d = 0; d < dep; d++) { 10 sums[d] += matrix[d][j]; 11 } 12 13 // find maxSum 14 int curSum = 0; 15 TreeSetsets = new TreeSet<>(); 16 // 不要忘记加入零 17 sets.add(0); 18 for (int sum : sums) { 19 curSum += sum; 20 Integer pre = sets.ceiling(curSum - k); 21 if (pre != null) { 22 maxSum = Math.max(maxSum, curSum - pre); 23 } 24 sets.add(curSum); 25 } 26 } 27 } 28 return maxSum; 29 } 30 }
1 public class Solution { 2 public int maxSumSubmatrix(int[][] matrix, int k) { 3 int len = matrix[0].length; 4 int dep = matrix.length; 5 int maxSum = Integer.MIN_VALUE; 6 for (int i = 0; i < len; i++) { 7 int[] sums = new int[dep]; 8 for (int j = i; j < len; j++) { 9 for (int d = 0; d < dep; d++) { 10 sums[d] += matrix[d][j]; 11 } 12 13 // find maxSum 14 int curResult = findMaxSub(sums, k); 15 maxSum = Math.max(maxSum, curResult); 16 } 17 } 18 return maxSum; 19 } 20 private int findMaxSub(int[] sums, int k) { 21 int len = sums.length; 22 int ans = Integer.MIN_VALUE; 23 int[] nums = new int[len]; 24 nums[0] = sums[0]; 25 for (int i = 0; i < len - 1; i++) { 26 nums[i + 1] = nums[i] + sums[i + 1]; 27 } 28 for (int i = 0; i < len; i++) { 29 for (int j = i; j < len; j++) { 30 int sum; 31 if (i == 0) { 32 sum = nums[j]; 33 } else { 34 sum = nums[j] - nums[i - 1]; 35 } 36 if (sum > ans && sum <= k) { 37 ans = sum; 38 } 39 } 40 } 41 return ans; 42 } 43 }
367. Valid Perfect Square
思路:采用二分法即可解决
1 class Solution { 2 public boolean isPerfectSquare(int num) { 3 if (num < 0) { 4 return false; 5 } 6 int start = 1; 7 int end = num; 8 while (start + 1 < end) { 9 long mid = (start + end) / 2; 10 if (mid * mid == num) { 11 return true; 12 } else if (mid * mid > num) { 13 end = (int) mid; 14 } else { 15 start = (int) mid; 16 } 17 } 18 if (start * start == num || end * end == num) { 19 return true; 20 } 21 return false; 22 } 23 }
注意:
1. 由于mid为两个数的和,可能超出int的范围,所以采用long类型
371. Sum of Two Integers
思路:看注释即可
1 public class Solution { 2 public int getSum(int a, int b) { 3 while (b != 0) { 4 int aa = a ^ b; // 不进位的加法 5 int bb = (a & b) << 1; // 各个位上的进位值 6 a = aa; 7 b = bb; 8 } 9 return a; 10 } 11 }
374. Guess Number Higher or Lower
思路:二分法
1 /* The guess API is defined in the parent class GuessGame. 2 @param num, your guess 3 @return -1 if my number is lower, 1 if my number is higher, otherwise return 0 4 int guess(int num); */ 5 6 public class Solution extends GuessGame { 7 public int guessNumber(int n) { 8 int start = 1; 9 int end = n; 10 while (start + 1 < end) { 11 int mid = start + (end - start) / 2; 12 int num = guess(mid); 13 if (num == 0) { 14 return mid; 15 } else if (num == -1) { 16 end = mid; 17 } else { 18 start = mid; 19 } 20 } 21 if (guess(start) == 0) { 22 return start; 23 } 24 return end; 25 } 26 }
383. Ransom Note
1 class Solution { 2 public boolean canConstruct(String ransomNote, String magazine) { 3 int[] array = new int[26]; 4 for (int i = 0; i < magazine.length(); i++) { 5 array[magazine.charAt(i) - 'a']++; 6 } 7 for (int i = 0; i < ransomNote.length(); i++) { 8 if (array[ransomNote.charAt(i) - 'a'] == 0) { 9 return false; 10 } 11 array[ransomNote.charAt(i) - 'a']--; 12 } 13 return true; 14 } 15 }
409. Longest Palindrome
思路:只要有一对相同的字符,就可构成一对回文串,最后中间可以放置一个字母(通过集合是否为空判断)
1 class Solution { 2 public int longestPalindrome(String s) { 3 if (s == null || s.length() == 0) { 4 return 0; 5 } 6 HashSethash = new HashSet<>(); 7 int count = 0; 8 for (int i = 0; i < s.length(); i++) { 9 if (hash.contains(s.charAt(i))) { 10 hash.remove(s.charAt(i)); 11 count++; 12 } else { 13 hash.add(s.charAt(i)); 14 } 15 } 16 if (!hash.isEmpty()) { 17 return count * 2 + 1; 18 } 19 return count * 2; 20 } 21 }
412. Fizz Buzz
1 class Solution { 2 public ListfizzBuzz(int n) { 3 List result = new ArrayList<>(); 4 for (int i = 1; i <= n; i++) { 5 if (i % 3 == 0 && i % 5 == 0) { 6 result.add("FizzBuzz"); 7 } else if (i % 3 == 0) { 8 result.add("Fizz"); 9 } else if (i % 5 == 0) { 10 result.add("Buzz"); 11 } else { 12 result.add(String.valueOf(i)); 13 } 14 } 15 return result; 16 } 17 }
414. Third Maximum Number
思路:采用Integer的自动拆装箱想法不错
1 class Solution { 2 public int thirdMax(int[] nums) { 3 Integer firstMax = null; 4 Integer secondMax = null; 5 Integer thirdMax = null; 6 for (Integer num : nums) { 7 if (num.equals(firstMax) || num.equals(secondMax) || num.equals(thirdMax)) { 8 continue; 9 } 10 if (firstMax == null || firstMax < num) { 11 thirdMax = secondMax; 12 secondMax = firstMax; 13 firstMax = num; 14 } else if (secondMax == null || secondMax < num) { 15 thirdMax = secondMax; 16 secondMax = num; 17 } else if (thirdMax == null || thirdMax < num) { 18 thirdMax = num; 19 } 20 } 21 return thirdMax == null ? firstMax : thirdMax; 22 } 23 }
415. Add Strings
1 class Solution { 2 public String addStrings(String num1, String num2) { 3 StringBuilder sb = new StringBuilder(); 4 int carry = 0; 5 for (int i = num1.length() - 1, j = num2.length() - 1; i >= 0 || j >= 0 || carry == 1; i--, j--) { 6 int x = i < 0 ? 0 : num1.charAt(i) - '0'; 7 int y = j < 0 ? 0 : num2.charAt(j) - '0'; 8 sb.append((x + y + carry) % 10); 9 carry = (x + y + carry) / 10; 10 } 11 return sb.reverse().toString(); 12 } 13 }
注意:
1. 字符串记得翻转
2. 两个字符串长度不同
434. Number of Segments in a String
1 class Solution { 2 public int countSegments(String s) { 3 int res = 0; 4 for (int i = 0; i < s.length(); i++) { 5 if (s.charAt(i) != ' ' && (i == 0 || s.charAt(i - 1) == ' ')) { 6 res++; 7 } 8 } 9 return res; 10 } 11 }
437. Path Sum III
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public int pathSum(TreeNode root, int sum) { 12 if (root == null) { 13 return 0; 14 } 15 return pathSumFrom(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum); 16 } 17 private int pathSumFrom(TreeNode node, int sum) { 18 if (node == null) { 19 return 0; 20 } 21 return (node.val == sum ? 1 : 0) + pathSumFrom(node.left, sum - node.val) + pathSumFrom(node.right, sum - node.val); 22 } 23 }
438. Find All Anagrams in a String
思路:滑动窗口算法,自信看discuss即可
1 class Solution { 2 public ListfindAnagrams(String s, String p) { 3 List res = new ArrayList<>(); 4 if (p.length() > s.length()) { 5 return res; 6 } 7 HashMap hash = new HashMap<>(); 8 for (char c : p.toCharArray()) { 9 hash.put(c, hash.getOrDefault(c, 0) + 1); 10 } 11 int start = 0; 12 int end = 0; 13 int counter = hash.size(); 14 while (end < s.length()) { 15 char c = s.charAt(end); 16 if (hash.containsKey(c)) { 17 hash.put(c, hash.get(c) - 1); 18 if (hash.get(c) == 0) { 19 counter--; 20 } 21 } 22 end++; 23 while (counter == 0) { 24 char tempc = s.charAt(start); 25 if (hash.containsKey(tempc)) { 26 hash.put(tempc, hash.get(tempc) + 1); 27 if (hash.get(tempc) > 0) { 28 counter++; 29 } 30 } 31 if (end - start == p.length()) { 32 res.add(start); 33 } 34 start++; 35 } 36 } 37 return res; 38 } 39 }
442. Find All Duplicates in an Array
思路:与438差不多
1 class Solution { 2 public ListfindDuplicates(int[] nums) { 3 List res = new ArrayList<>(); 4 if (nums == null || nums.length == 0) { 5 return res; 6 } 7 for (int i = 0; i < nums.length; i++) { 8 int val = Math.abs(nums[i]) - 1; 9 if (nums[val] < 0) { 10 res.add(val + 1); 11 } 12 nums[val] = -nums[val]; 13 } 14 return res; 15 } 16 }
447. Number of Boomerangs
思路:
1 class Solution { 2 public int numberOfBoomerangs(int[][] points) { 3 if (points == null || points.length < 3) { 4 return 0; 5 } 6 int len = points.length; 7 int res = 0; 8 for (int i = 0; i < len; i++) { 9 HashMapmapping = new HashMap<>(); 10 for (int j = 0; j < len; j++) { 11 if (i == j) { 12 continue; 13 } 14 int x = points[j][0] - points[i][0]; 15 int y = points[j][1] - points[i][1]; 16 int d = x * x + y * y; 17 mapping.put(d, mapping.getOrDefault(d, 0) + 1); 18 } 19 20 for (Map.Entry map : mapping.entrySet()) { 21 int value = map.getValue(); 22 res += value * (value - 1); 23 } 24 } 25 return res; 26 } 27 }
448. Find All Numbers Disappeared in an Array
思路:所有出现的数字置为小于0,再次循环,大于零的位置即为未出现的数字
1 class Solution { 2 public ListfindDisappearedNumbers(int[] nums) { 3 List res = new ArrayList<>(); 4 for (int i = 0; i < nums.length; i++) { 5 int val = Math.abs(nums[i]) - 1; 6 if (nums[val] > 0) { 7 nums[val] = -nums[val]; 8 } 9 } 10 for (int i = 0; i < nums.length; i++) { 11 if (nums[i] > 0) { 12 res.add(i + 1); 13 } 14 } 15 return res; 16 } 17 }
453. Minimum Moves to Equal Array Elements
1 /** 2 * 数学证明:假设sum为该数字的和,min为数组的最小值,n为数组的长度,m是移动的步数,x是最后相等的数字 3 * 因此,sum + m * (n - 1) = m * x 4 * 而,x - min = m 5 * 综合以上两个等式,可求得sum - min * n = m(此时就求得了移动的步数) 6 */ 7 class Solution { 8 public int minMoves(int[] nums) { 9 int sum = 0; 10 int min = Integer.MAX_VALUE; 11 int n = nums.length; 12 for (int i = 0; i < n; i++) { 13 sum += nums[i]; 14 min = Math.min(min, nums[i]); 15 } 16 return sum - min * n; 17 } 18 }
498. Diagonal Traverse
思路:自己也没有推出规律,看了Discuss,看程序即可明白
1 public class Solution { 2 public int[] findDiagonalOrder(int[][] matrix) { 3 if (matrix == null || matrix.length == 0) { 4 return new int[0]; 5 } 6 if (matrix[0] == null || matrix[0].length == 0) { 7 return new int[0]; 8 } 9 int length = matrix[0].length; 10 int depth = matrix.length; 11 int[] result = new int [length * depth]; 12 int direction = 0; 13 int row = 0; 14 int col = 0; 15 int[][] coordinate = {{-1, 1}, {1, -1}}; 16 for (int i = 0; i < length * depth; i++) { 17 result[i] = matrix[row][col]; 18 row += coordinate[direction][0]; 19 col += coordinate[direction][1]; 20 21 if (row >= depth) { 22 row = depth - 1; 23 col += 2; 24 direction = 1 - direction; 25 } else if (col >= length) { 26 row += 2; 27 col = length - 1; 28 direction = 1 - direction; 29 } else if (row < 0) { 30 row = 0; 31 direction = 1 - direction; 32 } else if (col < 0) { 33 col = 0; 34 direction = 1 - direction; 35 } 36 } 37 return result; 38 } 39 }
1 public class Solution { 2 public int[] findDiagonalOrder(int[][] matrix) { 3 if (matrix == null || matrix.length == 0) { 4 return new int[0]; 5 } 6 int length = matrix[0].length; 7 int depth = matrix.length; 8 int row = 0; 9 int col = 0; 10 int[] result = new int[length * depth]; 11 for (int i = 0; i < length * depth; i++) { 12 result[i] = matrix[row][col]; 13 // 先判断是否超出depth和length 14 if ((row + col) % 2 == 0) { 15 if (col == length - 1) { 16 row++; 17 } else if (row == 0) { 18 col++; 19 } else { 20 row--; 21 col++; 22 } 23 } else { 24 if (row == depth - 1) { 25 col++; 26 } else if (col == 0) { 27 row++; 28 } else { 29 row++; 30 col--; 31 } 32 } 33 } 34 return result; 35 } 36 }
506. Relative Ranks
思路:采用新的二维数组存储原数组与其位置,然后排序,按照要求赋值即可
1 public class Solution { 2 public String[] findRelativeRanks(int[] nums) { 3 int len = nums.length; 4 int[][] pairs = new int[len][2]; 5 for (int i = 0; i < len; i++) { 6 pairs[i][0] = nums[i]; 7 pairs[i][1] = i; 8 } 9 Arrays.sort(pairs, (o1, o2) -> (o2[0] - o1[0])); 10 11 String[] results = new String[len]; 12 for (int i = 0; i < len; i++) { 13 if (i == 0) { 14 results[pairs[i][1]] = "Gold Medal"; 15 } else if (i == 1) { 16 results[pairs[i][1]] = "Silver Medal"; 17 } else if (i == 2) { 18 results[pairs[i][1]] = "Bronze Medal"; 19 } else { 20 results[pairs[i][1]] = i + 1 + ""; 21 } 22 } 23 return results; 24 } 25 }
521. Longest Uncommon Subsequence I
思路:由于最长的非公共子序列一定是比较其本身,因此,当两个字符串相等时,不存在非公共子序列;当不等时,最长的非公共子序列一定是两个字符串中最长的长度
1 public class Solution { 2 public int findLUSlength(String a, String b) { 3 return a.equals(b) ? -1 : Math.max(a.length(), b.length()); 4 } 5 }
522. Longest Uncommon Subsequence II
思路:遍历整个数组,得到数组内所有字符串的子序列,并放入到hashMap中,其中key为得到的所有子序列,value为每个子序列出现的次数,最后hashMap中出现次数为1的即为非公共子序列,求出最长的即可
1 public class Solution { 2 public int findLUSlength(String[] strs) { 3 Mapmapping = new HashMap<>(); 4 for (String str : strs) { 5 for (String s : getSubseqs(str)) { 6 mapping.put(s, mapping.getOrDefault(s, 0) + 1); 7 } 8 } 9 int longest = -1; 10 for (Map.Entry entry : mapping.entrySet()) { 11 if (entry.getValue() == 1) { 12 longest = Math.max(longest, entry.getKey().length()); 13 } 14 } 15 return longest; 16 } 17 public Set getSubseqs(String str) { 18 Set res = new HashSet<>(); 19 if (str.length() == 0) { 20 res.add(""); 21 return res; 22 } 23 Set subRes = getSubseqs(str.substring(1)); 24 res.addAll(subRes); 25 for (String seq : subRes) { 26 res.add(str.charAt(0) + seq); 27 } 28 return res; 29 } 30 }
540. Single Element in a Sorted Array
思路:将位置为偶数的进行二分,记得要判断mid的奇偶
1 class Solution { 2 public int singleNonDuplicate(int[] nums) { 3 int start = 0; 4 int end = nums.length - 1; 5 int mid = start + (end - start) / 2; 6 while (start + 1 < end) { 7 if (mid % 2 == 1) { 8 if (nums[mid] == nums[mid - 1]) { 9 start = mid + 1; 10 } else if (nums[mid] == nums[mid + 1]) { 11 end = mid - 1; 12 } else { 13 return nums[mid]; 14 } 15 } else { 16 if (nums[mid] == nums[mid + 1]) { 17 start = mid + 2; 18 } else if (nums[mid] == nums[mid - 1]) { 19 end = mid - 2; 20 } else { 21 return nums[mid]; 22 } 23 } 24 mid = start + (end - start) / 2; 25 } 26 return nums[mid]; 27 } 28 }
547. Friend Circles
方法一:采用深度优先搜索
1 class Solution { 2 public int findCircleNum(int[][] M) { 3 int[] visited = new int[M.length]; 4 int res = 0; 5 for (int i = 0; i < M.length; i++) { 6 if (visited[i] == 0) { 7 dfsHelper(M, visited, i); 8 res++; 9 } 10 } 11 return res; 12 } 13 private void dfsHelper(int[][] M, int[] visited, int i) { 14 int len = M.length; 15 for (int j = 0; j < len; j++) { 16 if (visited[j] == 0 && M[i][j] == 1) { 17 visited[j] = 1; 18 dfsHelper(M, visited, j); 19 } 20 } 21 } 22 }
方法二:采用并查集
1 class Solution { 2 private class UnionFind { 3 private int count; 4 private int[] parent, height; 5 6 public UnionFind(int n) { 7 count = n; 8 parent = new int[n]; 9 height = new int[n]; 10 for (int i = 0; i < n; i++) { 11 parent[i] = i; 12 } 13 } 14 public int find(int x) { 15 while (x != parent[x]) { 16 parent[x] = parent[parent[x]]; 17 x = parent[x]; 18 } 19 return x; 20 } 21 public void union(int x, int y) { 22 int rootX = find(x); 23 int rootY = find(y); 24 if (rootX == rootY) { 25 return; 26 } 27 if (height[rootX] > height[rootY]) { 28 parent[rootY] = rootX; 29 } else { 30 parent[rootX] = rootY; 31 if (height[rootX] == height[rootY]) { 32 height[rootY]++; 33 } 34 } 35 count--; 36 } 37 public int count() { 38 return count; 39 } 40 } 41 public int findCircleNum(int[][] M) { 42 int len = M.length; 43 UnionFind res = new UnionFind(len); 44 for (int i = 0; i < len - 1; i++) { 45 for (int j = i + 1; j < len; j++) { 46 if (M[i][j] == 1) { 47 res.union(i, j); 48 } 49 } 50 } 51 return res.count(); 52 } 53 }
注意:
1. 采用union find方法时要注意count的变换,每次union的时候都要讲count自减一
563. Binary Tree Tilt
思路:采用后序遍历的方法
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 int res = 0; 12 public int findTilt(TreeNode root) { 13 postOrder(root); 14 return res; 15 } 16 public int postOrder(TreeNode root) { 17 if (root == null) { 18 return 0; 19 } 20 int left = postOrder(root.left); 21 int right = postOrder(root.right); 22 23 res += Math.abs(left - right); 24 return left + right + root.val; 25 } 26 }
565. Array Nesting
思路:
方法一:使用hashSet不停地添加,但是不需要将数组元素全部遍历,只需要遍历没有在set中的数字即可
1 class Solution { 2 public int arrayNesting(int[] nums) { 3 HashSethash = new HashSet<>(); 4 int res = 0; 5 for (int num : nums) { 6 int cur = num; 7 int curRes = 0; 8 while (hash.add(cur)) { 9 cur = nums[cur]; 10 curRes++; 11 } 12 res = Math.max(res, curRes); 13 } 14 return res; 15 } 16 }
方法二:不使用hashSet
1 class Solution { 2 public int arrayNesting(int[] nums) { 3 int res = Integer.MIN_VALUE; 4 for (int i = 0; i < nums.length; i++) { 5 if (nums[i] != -1) { 6 int cur = i; 7 int curRes = 0; 8 while (nums[cur] != -1) { 9 curRes++; 10 int mid = nums[cur]; 11 nums[cur] = -1; 12 cur = mid; 13 } 14 res = Math.max(res, curRes); 15 } 16 } 17 return res; 18 } 19 }
640. Solve the Equation
思路:按照等号划分为两部分,并将系数与常数合并即可
1 public class Solution { 2 public String solveEquation(String equation) { 3 int[] frag = read(equation.split("=")[0]); 4 int[] frag1 = read(equation.split("=")[1]); 5 frag[0] -= frag1[0]; 6 frag[1] = frag1[1] - frag[1]; 7 if (frag[0] == 0 && frag[1] == 0) { 8 return "Infinite solutions"; 9 } else if (frag[0] == 0) { 10 return "No solution"; 11 } 12 return "x=" + frag[1] / frag[0]; 13 } 14 private int[] read(String str) { 15 int[] res = new int[2]; 16 String[] strs = str.split("(?=[+-])"); 17 for (int i = 0; i < strs.length; i++) { 18 if (strs[i].equals("x") || strs[i].equals("+x")) { 19 res[0]++; 20 } else if (strs[i].equals("-x")) { 21 res[0]--; 22 } else if (strs[i].contains("x")) { 23 res[0] += Integer.parseInt(strs[i].substring(0, strs[i].indexOf("x"))); 24 } else { 25 res[1] += Integer.parseInt(strs[i]); 26 } 27 } 28 return res; 29 } 30 }
659. Split Array into Consecutive Subsequences
思路:
673. Number of Longest Increasing Subsequence
思路:如同题目300,只是多了一个数组记录当前LIS的数量
1 class Solution { 2 public int findNumberOfLIS(int[] nums) { 3 if (nums == null || nums.length == 0) { 4 return 0; 5 } 6 int n = nums.length, maxLen = 0, res = 0; 7 int[] len = new int[n], cnt = new int[n]; 8 for (int i = 0; i < n; i++) { 9 len[i] = cnt[i] = 1; 10 for (int j = 0; j < i; j++) { 11 if (nums[i] > nums[j]) { 12 if (len[i] == len[j] + 1) { 13 cnt[i] += cnt[j]; 14 } 15 if (len[i] < len[j] + 1) { 16 len[i] = len[j] + 1; 17 cnt[i] = cnt[j]; 18 } 19 } 20 } 21 if (maxLen == len[i]) { 22 res += cnt[i]; 23 } 24 if (maxLen < len[i]) { 25 maxLen = len[i]; 26 res = cnt[i]; 27 } 28 } 29 return res; 30 } 31 }
946. Validate Stack Sequences
思路:
1 class Solution { 2 public boolean validateStackSequences(int[] pushed, int[] popped) { 3 Stackstack = new Stack<>(); 4 int index = 0; 5 for (int p : pushed) { 6 stack.push(p); 7 while (!stack.isEmpty() && stack.peek() == popped[index]) { 8 stack.pop(); 9 index++; 10 } 11 } 12 return stack.isEmpty(); 13 } 14 }