<center>#1 Two Sum</center>
- link
- Description:
- Given an array of integers, return indices of the two numbers such that they add up to a specific target.
- Input: [2, 7, 11, 15]
- Output: [0, 1]
- Assumptions:
- each input would have exactly one solution
- you may not use the same element twice
- Solution:
- Two Sum 的題一般有兩種解法姚建, 一種是用hash限书, 一種是用兩根指針。對于本題來說狱掂,用hash只需要遍歷一遍數(shù)組楼吃,所以在時間復雜度上要優(yōu)于兩根指針始花,因為兩個指針的方法是基于排序數(shù)組。
- Java中提供了HashMap的實現(xiàn)所刀。 Map以數(shù)組元素為Key衙荐, 以索引為Value。
- 遍歷一遍數(shù)組浮创, 先在map中尋找是否有元素能夠和當前值組成sum為target忧吟, 這個查找是O(1)的復雜度, 如果沒有斩披,就把當前值和索引作為一個鍵值對保存在Map中供后續(xù)查找溜族, 保存也是O(1)的復雜度。Worst Case是遍歷整個數(shù)組垦沉,也就是O(n)煌抒。
- Code:
# code block class Solution { public int[] twoSum(int[] nums, int target) { /* * Two Sum的題變種很多,所以第一個要關注的就是Assumption厕倍,本題是 * 最原始的two sum寡壮, 只有一個答案, 并且同一個元素不能用兩次 * */ // 校驗:本題的assumption確保有至少一個解讹弯,所以該步可以省略 if (nums == null || nums.length < 2) { return new int[0]; } // intialize the result int[] result = new int[0]; Map<Integer, Integer> map = new HashMap<>(); for (int i = 0; i < nums.length; i++) { if (map.containsKey(target - nums[i])) { result = new int[2]; result[0] = map.get(target - nums[i]); result[1] = i; return result; } map.put(nums[i], i); } return result; } }
- Time Complexity: O(n)
- Space Complexity: O(n)
<center>#2 Add Two Numbers</center>
- link
- Description:
- You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
- You may assume the two numbers do not contain any leading zero, except the number 0 itself.
- Input:
- Output:
- Assumptions:
- two numbers do not contain any leading zero, except the number 0 itself.
- Solution:
- 注意點:
- 使用dummy node
- 處理到所有case:
- l1 或 l2 位 null
- l1 l2長度相等
- l1 長于 l2
- l2 長于 l1
- 答案需要進位
- 注意點:
- Code:
# code block public ListNode addTwoNumbers(ListNode l1, ListNode l2) { if (l1 == null) { return l2; } if (l2 == null) { return l1; } int carrier = 0; ListNode dummy = new ListNode(0); ListNode curr = dummy; while (l1 != null && l2 != null) { int val = l1.val + l2.val + carrier; curr.next = new ListNode(val % 10); curr = curr.next; carrier = val / 10; l1 = l1.next; l2 = l2.next; } while (l1 != null) { int val = l1.val + carrier; curr.next = new ListNode(val % 10); curr = curr.next; carrier = val / 10; l1 = l1.next; } while (l2 != null) { int val = l2.val + carrier; curr.next = new ListNode(val % 10); curr = curr.next; carrier = val / 10; l2 = l2.next; } if (carrier != 0) { curr.next = new ListNode(carrier); } return dummy.next; }
- Time Complexity: O(max(m, n))
- Space Complexity: O(1)
<center>#3 Longest Substring Without Repeating Characters</center>
- link
- Description:
- Given a string, find the length of the longest substring without repeating characters.
- Input: "abcabcbb"
- Output: 3
- Solution:
- 典型的同向型兩根指針問題的區(qū)間類問題况既。
- 維持一個符合條件的區(qū)間,每次更新最大值
- Code:
# code block public int lengthOfLongestSubstring(String s) { if (s == null || s.length() == 0) { return 0; } boolean[] hash = new boolean[256]; char[] sc = s.toCharArray(); int result = 0; int left = 0, right = 0; while (right < sc.length) { while (right < sc.length && hash[sc[right]] == false) { hash[sc[right]] = true; right++; } result = Math.max(result, right - left); hash[sc[left]] = false; left++; } return result; }
- Time Complexity: O(n)
- Space Complexity: O(1)
<center>#4 Median of Two Sorted Arrays</center>
- link
- Description:
- There are two sorted arrays nums1 and nums2 of size m and n respectively.
- Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
- Input: nums1 = [1, 2] nums2 = [3, 4]
- Output:2.5
- Assumptions:
- At least one of this two arrays has more than 0 element.
- Solution:
- 要求時間復雜度為O(log (m+n)), 這題可以由時間復雜度倒推方法
- 滿足O(log n)時間復雜度的算法第一個想到的是二分组民,又是排序數(shù)組棒仍,更加確定是二分
- 求第k個數(shù),每次把問題縮小到排除不可能的k / 2 個數(shù)
- 對兩個數(shù)組同時找到第k / 2 個數(shù)臭胜,如果第一個數(shù)組中的數(shù)小于第二個數(shù)組中的數(shù)莫其,那么第一個數(shù)組中必然不存在第k大的數(shù),可以排除前k / 2 的數(shù)耸三,反之同理
- 遞歸執(zhí)行乱陡,注意遞歸的出口和corner case
- Code:
# code block public double findMedianSortedArrays(int[] nums1, int[] nums2) { if (nums1 == null) { // prevent null exception nums1 = new int[0]; } if (nums2 == null) { nums2 = new int[0]; } int m = nums1.length; int n = nums2.length; // 1-based index int k = (m + n + 1) / 2; int median1 = findK(nums1, nums2, 0, 0, k); if ((m + n) % 2 == 1) { // total number is odd return (double)median1; } int median2 = findK(nums1, nums2, 0, 0, k + 1); // Remind of the conversion from int to double return (median1 + median2) / 2.0; } private int findK(int[] nums1, int[] nums2, int start1, int start2, int k) { int m = nums1.length, n = nums2.length; if (start1 >= m) { return nums2[start2 + k - 1]; } if (start2 >= n) { return nums1[start1 + k - 1]; } if (k == 1) { return Math.min(nums1[start1], nums2[start2]); } int mid = k / 2; // make sure never drop the val1 when start1 + mid - 1 >= m int val1 = (start1 + mid - 1 < m) ? nums1[start1 + mid - 1] : Integer.MAX_VALUE; int val2 = (start2 + mid - 1 < n) ? nums2[start2 + mid - 1] : Integer.MAX_VALUE; if (val1 < val2) { // drop amount of mid number in nums1 return findK(nums1, nums2, start1 + mid, start2, k - mid); } else { return findK(nums1, nums2, start1, start2 + mid, k - mid); } }
- Time Complexity: O(log (m+n))
- Space Complexity: O(1)
<center>#5 Longest Palindromic Substring</center>
- link
- Description:
- Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
- Input: "babad"
- Output: "bab" or "aba"
- Solution:
- 求最長子回文串,brute force的解法是三重循環(huán)仪壮,一重確定起點憨颠,一重確定終點,一重驗證是否為回文串睛驳。復雜度為O(n^3)
- 這邊想到的優(yōu)化是如果我以一個點為中點烙心,來找以這個點為中點的最長回文串
- 這樣一重循環(huán)確定中點,一重循環(huán)找最長回文串乏沸,時間復雜度就降到O(n^2)
- 注意點是回文串要考慮到奇數(shù)長度和偶數(shù)長度兩種特殊情形
- Code:
# code block public String longestPalindrome(String s) { if (s == null || s.length() < 2) { return s; } for (int i = 0; i < s.length(); i++) { updateLongest(s, i, i); if (i != s.length() - 1 && s.charAt(i) == s.charAt(i + 1)) { updateLongest(s, i, i + 1); } } return s.substring(start, end + 1); } private void updateLongest(String s, int l, int r) { while (l >= 0 && r < s.length()) { if (s.charAt(l) != s.charAt(r)) { break; } if (r - l > end - start) { start = l; end = r; } l--; r++; } } private int start = 0; private int end = 0;
- Time Complexity: O(n ^ 2)
- Space Complexity: O(1)
<center>#6 ZigZag Conversion</center>
- link
- Description:
- The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
- Input: "PAYPALISHIRING", 3
- Output: "PAHNAPLSIIGYIR"
- Solution:
- 借用網(wǎng)上摘來的圖表達題意
- [圖片上傳失敗...(image-eb60d7-1534568626309)]
- 這是一道模擬題淫茵,可以找到規(guī)律是以2 * numRows - 2 在循環(huán)
- corner case: numRos = 1 時就是原字符串
- Code:
# code block public String convert(String s, int numRows) { if (s == null || s.length() <= numRows || numRows <= 1) { return s; } int sep = numRows * 2 - 2; char[] sc = s.toCharArray(); StringBuilder[] sb = new StringBuilder[numRows]; for (int i = 0; i < sb.length; i++) { sb[i] = new StringBuilder(); } for (int i = 0; i < sc.length; i++) { int idx = i % sep; if (idx < numRows) { sb[idx].append(sc[i]); } else { sb[sep - idx].append(sc[i]); } } StringBuilder result = new StringBuilder(); for (int i = 0; i < sb.length; i++) { result.append(sb[i]); } return result.toString(); }
- Time Complexity: O(n)
- Space Complexity: O(n)
<center>#7 Reverse Integer</center>
- link
- Description: Reverse Integer
- Reverse digits of an integer.
- Input: 123
- Output: 321
- Assumptions:
- return 0 when the reversed integer overflows.
- Solution:
- 注意點:
- 檢查overflow,注釋位置為詳細解法
- 注意java負數(shù)取余為負數(shù)
- 注意點:
- Code:
# code block public int reverse(int x) { boolean isPos = (x >= 0) ? true : false; int result = 0; while (x / 10 != 0 || x % 10 != 0) { int val = result * 10 + Math.abs(x % 10); // check overflow if (val / 10 != result) { return 0; } result = val; x /= 10; } return isPos? result : -result; }
- Time Complexity: O(number of digits)
- Space Complexity: O()
<center>#8 String to Integer (atoi)</center>
- link
- Description:
- Implement atoi to convert a string to an integer.
- Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases.
- Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front.
- Input: " -0012a42"
- Output: -12
- Solution:
- 注意考慮所有Corner Case:
- null
- empty string
- positive or negative
- start with space
- overflow (max and min are different)
- 方法二:轉換成long型來判斷
- 注意考慮所有Corner Case:
- Code:
# code block public int myAtoi(String str) { if (str == null) { // prevent null exception return 0; } str = str.trim(); if (str.length() == 0) { // emtpy string return 0; } int result = 0; boolean isPos = true; char[] sc = str.toCharArray(); int i = 0; // postive or negative if (Character.isDigit(sc[0])) { isPos = true; } else if (sc[0] == '+') { isPos = true; i = 1; } else if (sc[0] == '-') { isPos = false; i = 1; } else { return 0; } for (; i < sc.length; i++) { if (!Character.isDigit(sc[i])) { // invalid string return result; } if (isPos) { int val = result * 10 + sc[i] - '0'; if (val / 10 != result) { // check overflow return Integer.MAX_VALUE; } result = val; } else { int val = result * 10 + '0' - sc[i]; if (val / 10 != result) { return Integer.MIN_VALUE; } result = val; } } return result; }
- Time Complexity: O(n)
- Space Complexity: O(n)
<center>#9 Palindrome Number</center>
- link
- Description:
- Determine whether an integer is a palindrome. Do this without extra space.
- Input: 121
- Output: true
- Solution:
- 注意點:
- 負數(shù)肯定不是
- 注意溢出
- 注意點:
- Code:
# code block public boolean isPalindrome(int x) { if (x < 0) { return false; } long org = x; long reverse = 0; while (x / 10 != 0 || x % 10 != 0) { reverse = reverse * 10 + x % 10; x /= 10; } return reverse == org; }
- Time Complexity: O(lg n)
- Space Complexity: O(1)
<center>#11 Container With Most Water</center>
- link
- Description:
- Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
- Input: [1,2,1]
- Output: 2
- Assumptions:
- You may not slant the container and n is at least 2.
- Solution:
- 典型的相向型兩根指針問題蹬跃。面積等于底乘高匙瘪。當兩根指針相向, 底只會越來越小蝶缀,所以只需要找到更高的高與當前最大值比較即可丹喻。
- 兩根線和x軸組成容器,選取短板做高翁都,所以每次更新短板碍论,就能更新高度。
- Code:
# code block public int maxArea(int[] height) { if (height == null || height.length <= 1) { return 0; } int max = 0; int left = 0, right = height.length - 1; while (left < right) { max = Math.max(max, Math.min(height[left], height[right]) * (right - left)); if (height[left] < height[right]) { left++; } else { right--; } } return max; }
- Time Complexity: O(n)
- Space Complexity: O(1)
<center>#12 Integer to Roman</center>
- link
- Description:
- Given an integer, convert it to a roman numeral.
- Input: 456
- Output: "CDLVI"
- Assumptions:
- Input is guaranteed to be within the range from 1 to 3999.
- Solution:
- 模擬題柄慰,要想知道羅馬數(shù)字的具體規(guī)則參考wikipedia
- Code:
# code block class Solution { public static final int[] number = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; public static final String[] symbol = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}; public String intToRoman(int num) { StringBuilder sb = new StringBuilder(); int i = 0; while (num != 0) { int times = num / number[i]; if (times != 0) { for (int j = 0; j < times; j++) { sb.append(symbol[i]); } num = num % number[i]; } i++; } return sb.toString(); } }
<center>#13 Roman to Integer</center>
- link
- Description:
- Given a roman numeral, convert it to an integer.
- Input: "CDLVI"
- Output: 456
- Assumptions:
- Input is guaranteed to be within the range from 1 to 3999.
- Solution:
- 模擬題鳍悠,要想知道羅馬數(shù)字的具體規(guī)則參考wikipedia
- Code:
# code block class Solution { public static final int[] number = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; public static final String[] symbol = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}; public int romanToInt(String s) { int result = 0; if (s == null || s.length() == 0) { return result; } StringBuilder sb = new StringBuilder(s); int i = 0; while (sb.length() > 0 && i < number.length) { String curr = symbol[i]; while (sb.length() >= curr.length() && sb.substring(0, curr.length()).equals(curr)) { result += number[i]; sb.delete(0, curr.length()); } i++; } return result; } }
<center>#14 Longest Common Prefix</center>
- link
- Description:
- Write a function to find the longest common prefix string amongst an array of strings.
- Input:["aasdfgas", "aaasafda"]
- Output:"aa"
- Solution:
- 多種解法
- 最巧妙地是排序之后比較首尾
- 二分也可以通過測試
- Code:
# code block public String longestCommonPrefix(String[] strs) { StringBuilder result = new StringBuilder(); if (strs!= null && strs.length > 0){ Arrays.sort(strs); char [] a = strs[0].toCharArray(); char [] b = strs[strs.length-1].toCharArray(); for (int i = 0; i < a.length; i ++){ if (b.length > i && b[i] == a[i]){ result.append(b[i]); } else { return result.toString(); } } return result.toString(); }
- Time Complexity: O(n lg n)
- Code:
# code block class Solution { public String longestCommonPrefix(String[] strs) { if (strs == null || strs.length == 0) { return ""; } int start = 0; int end = Integer.MAX_VALUE; for (String str : strs) { end = Math.min(end, str.length()); } end--; while (start < end - 1) { int mid = start + (end - start) / 2; if (checkValid(mid, strs)) { start = mid; } else { end = mid; } } if (checkValid(end, strs)) { return strs[0].substring(0, end + 1); } if (checkValid(start, strs)) { return strs[0].substring(0, start + 1); } return ""; } private boolean checkValid(int n, String[] strs) { String tmp = strs[0].substring(0, n + 1); for(int i = 1; i < strs.length; i++) { if (!strs[i].substring(0, n + 1).equals(tmp)) { return false; } } return true; } }
<center>#15 3Sum</center>
- link
- Description:
- Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
- Input: [-1, 0, 1, 2, -1, -4]
- Output: [[-1, 0, 1], [-1, -1, 2]]
- Assumptions:
- The solution set must not contain duplicate triplets
- Solution:
- Two sum 變種∽Γ可以簡化為固定一個值藏研,在剩下的值中尋找two sum。難點在于去重概行,去重即聯(lián)想到排序蠢挡!所以先把數(shù)組排序。if (i != 0 && nums[i] == nums[i - 1]) 就continue這種方法確保了每個數(shù)字只取第一個凳忙。在two sum中兩個while循環(huán)確保相同的組合只出現(xiàn)一次业踏。
- Code:
# code block public List<List<Integer>> threeSum(int[] nums) { /* * 2 Sum的變種, 可以簡化為確定一個數(shù)a消略, 在剩下的數(shù)中的2 Sum為target - a * 難點堡称,去重 */ // Initialize the result List<List<Integer>> result = new ArrayList<>(); // Boundary case if (nums == null || nums.length < 3) { return result; } // The two pointer solution for two sum is based on sorted array Arrays.sort(nums); for (int i = 0; i < nums.length - 2; i++) { // remove duplicates if (i != 0 && nums[i] == nums[i - 1]) { continue; } int left = i + 1, right = nums.length - 1; while (left < right) { int val = nums[i] + nums[left] + nums[right]; if (val == 0) { // find one solution List<Integer> solution = new ArrayList<>(); solution.add(nums[i]); solution.add(nums[left]); solution.add(nums[right]); result.add(solution); left++; right--; // remove duplicates while (left < right && nums[left] == nums[left - 1]) { left++; } while (left < right && nums[right] == nums[right + 1]) { right--; } } else if (val > 0) { // drop the right right--; } else { // drop the left left++; } } } return result; }
- Time Complexity: O(n ^ 2)
- Space Complexity: O(1)
<center>#16 3Sum Closest</center>
-
Description:
- Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.
Input: [2, 7, 11, 15]
Output: [0, 1]
-
Assumptions:
- assume that each input would have exactly one solution.
-
Solution:
- 3Sum的變種, 保存一個與target的差值艺演, 每次作比較却紧,小于這個差值即更新答案。
- 注意點:
- 三個int相加使用long防止溢出
- 3Sum的變種, 保存一個與target的差值艺演, 每次作比較却紧,小于這個差值即更新答案。
-
Code:
# code block public int threeSumClosest(int[] nums, int target) { Arrays.sort(nums); long diff = (long)Integer.MAX_VALUE * 2; int result = 0; // 3 Sum template for (int i = 0; i < nums.length - 2; i++) { int left = i + 1, right = nums.length - 1; while (left < right) { long val = nums[i] + nums[left] + nums[right]; if (Math.abs(val - target) < Math.abs(diff)) { diff = val - target; result = (int)val; } // when val == target, it must be the answer if (val == target) { return target; } else if (val > target) { right--; } else { left++; } } } return result; }
Time Complexity: O(n ^ 2)
Space Complexity: O(n)
<center>#17 Letter Combinations of a Phone Number</center>
- link
- Description:
- Given a digit string, return all possible letter combinations that the number could represent.
- A mapping of digit to letters (just like on the telephone buttons) is given below.
- avator
- Input: Digit string "23"
- Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]
- Assumptions:
- The digits are between 2 and 9
- Solution:
- 求組合的題胎撤,在隱式圖上做DFS
- 注意點:
- 沒有明顯的回溯痕跡是因為String是immutable的類晓殊,每次修改都會形成一個新的對象
- Code:
# code block class Solution { public List<String> letterCombinations(String digits) { List<String> result = new ArrayList<>(); if (digits == null || digits.length() == 0) { return result; } char[] dc = digits.toCharArray(); dfsHelper(dc, 0, "", result); return result; } private void dfsHelper(char[] dc, int start, String curr, List<String> result) { if (start == dc.length) { result.add(curr); return; } char[] letters = pad[dc[start] - '0'].toCharArray(); for (char letter : letters) { dfsHelper(dc, start + 1, curr + letter, result); } } public static final String[] pad = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; }
<center>#18 4Sum</center>
- link
- Description:
- Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
- Input: [1, 0, -1, 0, -2, 2]
- Output: [[-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2]]
- Assumptions:
- solution set must not contain duplicate quadruplets.
- Solution:
- Two sum 變種。固定兩個值伤提,在剩下的值中做two sum巫俺,注意點和3Sum一樣還是排序和去重。
- Code:
# code block public List<List<Integer>> fourSum(int[] nums, int target) { List<List<Integer>> result = new ArrayList<>(); if (nums == null || nums.length < 4) { return result; } Arrays.sort(nums); for (int i = 0; i < nums.length - 3; i++) { if (i != 0 && nums[i] == nums[i - 1]) { continue; } for (int j = i + 1; j < nums.length - 2; j++) { if (j != i + 1 && nums[j] == nums[j - 1]) { continue; } twoSum(nums, j + 1, target, nums[i], nums[j], result); } } return result; } private void twoSum(int[] nums, int left, int target, int v1, int v2, List<List<Integer>> result) { int right = nums.length - 1; while (left < right) { long val = v1 + v2 + nums[left] + nums[right]; if (val == target) { List<Integer> solution = new ArrayList<>(); solution.add(v1); solution.add(v2); solution.add(nums[left]); solution.add(nums[right]); result.add(solution); left++; right--; while (left < right && nums[left] == nums[left - 1]) { left++; } while (left < right && nums[right] == nums[right + 1]) { right--; } } else if (val > target) { right--; } else { left++; } } }
- Time Complexity: O(n ^ 3)
- Space Complexity: O(1)
<center>#19 Remove Nth Node From End of List</center>
- link
- Description:
- Given a linked list, remove the nth node from the end of list and return its head.
- Input: 1->2->3->4->5 n = 2
- Output: 1->2->3->5
- Assumptions:
- Given n will always be valid.
- Try to do this in one pass.
- Solution:
- 使用dummynode因為可能要刪除第一個元素
- 使用兩根指針保持距離即可
- Code:
# code block public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy = new ListNode(0); ListNode slow = dummy; ListNode fast = dummy; dummy.next = head; for (int i = 0; i < n; i++) { if (fast == null) { return head; } fast = fast.next; } while (fast.next != null) { fast = fast.next; slow = slow.next; } slow.next = slow.next.next; return dummy.next; }
- Time Complexity: O(n)
- Space Complexity: O(1)
<center>#20 Valid Parentheses</center>
- link
- Description:
- Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
- The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and "([)]" are not.
- Input: "()[]{}"
- Output: true
- Solution:
- 模擬題肿男,用棧來做最適合介汹,注意corner case
- Code:
# code block public boolean isValid(String s) { if (s == null || s.length() == 0) { return true; } char[] sc = s.toCharArray(); Stack<Character> stack = new Stack<>(); for (char c : sc) { if (c == '(' || c == '[' || c == '{') { stack.push(c); } else { if (stack.isEmpty()) { return false; } if (c == ')' && stack.peek() != '(') { return false; } if (c == ']' && stack.peek() != '[') { return false; } if (c == '}' && stack.peek() != '{') { return false; } stack.pop(); } } return stack.isEmpty(); }
- Time Complexity: O(n)
- Space Complexity: O(n)
<center>#21 Merge Two Sorted Lists</center>
- link
- Description:
- Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.
- Input: 1->3->5->null 2->4->6->7->null
- Output:1->2->3->4->5->6->7->null
- Solution:
- 歸并排序
- 注意所有corner case
- Code:
# code block public ListNode mergeTwoLists(ListNode l1, ListNode l2) { if (l1 == null) { return l2; } if (l2 == null) { return l1; } ListNode dummy = new ListNode(0); ListNode curr = dummy; while (l1 != null && l2 != null) { ListNode tmp = null; if (l1.val < l2.val) { tmp = l1; l1 = l1.next; tmp.next = null; } else { tmp = l2; l2 = l2.next; tmp.next = null; } curr.next = tmp; curr = curr.next; } if (l1 != null) { curr.next = l1; } if (l2 != null) { curr.next = l2; } return dummy.next; }
- Time Complexity: O(m + n)
- Space Complexity: O(1)
<center>#22 Generate Parentheses</center>
- link
- Description:
- Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
- Input: 3
- Output: ["((()))", "(()())", "(())()", "()(())", "()()()"]
- Solution:
- 排列題却嗡,用隱式圖DFS遍歷
- String 是immutable類,不用特意回溯
- 剪枝: 當左邊括號和右邊括號數(shù)量相等時嘹承,可以省去加右邊括號的搜索
- Code:
# code block public List<String> generateParenthesis(int n) { List<String> result = new ArrayList<>(); if (n < 0) { return result; } dfsHelper(0, 0, n, "", result); return result; } private void dfsHelper(int left, int right, int n, String state, List<String> result) { if (left == n && right == n) { result.add(state); } if (left < n) { dfsHelper(left + 1, right, n, state + "(", result); } // 剪枝 if (right < left) { dfsHelper(left, right + 1, n, state + ")", result); } }
<center>#23 Merge k Sorted Lists</center>
- link
- Description:
- Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
- Input: [[1,2],[3,6],[4,5]];
- Output:[1,2,3,4,5,6]
- Solution:
- 歸并k個list窗价,往歸并排序的方向去想
- 歸并排序兩個list中去小的那一個的值,k個list就是取k個list中最小的那個值
- 聯(lián)想到heap叹卷, java中有heap的不完全實現(xiàn)priorityqueue
- 要學會寫java中的comparator
- Code:
# code block public ListNode mergeKLists(ListNode[] lists) { if (lists == null || lists.length == 0) { return null; } ListNode dummy = new ListNode(0); ListNode curr = dummy; Queue<ListNode> pq = new PriorityQueue<>(lists.length + 1, new Comparator<ListNode>() { @Override public int compare(ListNode a, ListNode b) { return a.val - b.val; } }); for (ListNode node : lists) { if (node != null) { pq.offer(node); } } while (!pq.isEmpty()) { ListNode min = pq.poll(); if (min.next != null) { pq.offer(min.next); } curr.next = min; curr = curr.next; } return dummy.next; }
- Time Complexity: O(n lg k)
- Space Complexity: O(1)
<center>#24 Swap Nodes in Pairs</center>
- link
- Description:
- Given a linked list, swap every two adjacent nodes and return its head.
- Input: 1->2->3->4
- Output: 2->1->4->3
- Assumptions:
- Your algorithm should use only constant space.
- You may not modify the values in the list, only nodes itself can be changed.
- Solution:
- 鏈表reverse題撼港,注意哪些指針要改變,注意子函數(shù)該返回什么骤竹,注意空鏈表處理
- Code:
# code block public ListNode swapPairs(ListNode head) { if (head == null || head.next == null) { return head; } ListNode dummy = new ListNode(0); dummy.next = head; ListNode prev = dummy; while ((prev = swap(prev)) != null); return dummy.next; } // prev->n1->n2->next // prev->n2->n1->next; // return n1 if swap, else return null private ListNode swap(ListNode prev) { if (prev.next == null || prev.next.next == null) { // No swap needed return null; } ListNode n1 = prev.next; ListNode n2 = n1.next; ListNode next = n2.next; prev.next = n2; n2.next = n1; n1.next = next; return n1; }
- Time Complexity: O(n)
- Space Complexity: O(1)
<center>#25 Reverse Nodes in k-Group</center>
- link
- Description:
- Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
- k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
- You may not alter the values in the nodes, only nodes itself may be changed.
- Only constant memory is allowed.
- Input: 1->2->3->4->5 k = 2
- Output: 2->1->4->3->5
- Solution:
- 翻轉時注意判斷是否需要翻轉帝牡,哪些指針需要被改變,返回什么節(jié)點
- Code:
# code block public ListNode reverseKGroup(ListNode head, int k) { if (k == 1) { return head; } ListNode dummy = new ListNode(0); dummy.next = head; ListNode prev = dummy; while ((prev = reverseK(prev, k)) != null); return dummy.next; } // prev->n1->n2->n3...->nk->next // prev->nk->nk-1->...->n1->next; // return n1 private ListNode reverseK(ListNode prev, int k) { ListNode nk = prev; for (int i = 0; i < k; i++) { nk = nk.next; if (nk == null) { return null; } } ListNode n1 = prev.next; ListNode nkPlus = nk.next; ListNode left = prev; ListNode right = prev.next; while (right != nkPlus) { ListNode tmp = right.next; right.next = left; left = right; right = tmp; } prev.next = nk; n1.next = nkPlus; return n1; }
- Time Complexity: O(n)
- Space Complexity: O(1)
<center>#26 Remove Duplicate</center>
- link
- Description:
- Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length
- Do not allocate extra space for another array, you must do this in place with constant memory.
- Input: [1,1,2]
- Output: 2
- Assumptions:
- Do not allocate extra space for another array, you must do this in place with constant memory.
- Solution:
- 考的就是最基本的去重, 關鍵在于注釋了remove the duplicate的那個if判斷
- Code:
# code block public int removeDuplicates(int[] nums) { if (nums == null || nums.length == 0) { return 0; } int idx = 0; for (int i = 0; i < nums.length; i++) { // remove the duplicate if (i != 0 && nums[i] == nums[i - 1]) { continue; } nums[idx] = nums[i]; idx++; } return idx; }
- Time Complexity: O(n)
- Space Complexity: O(1)
<center>#27 Remove Element</center>
- link
- Description:
- Given an array and a value, remove all instances of that value in place and return the new length.
- Do not allocate extra space for another array, you must do this in place with constant memory.
- The order of elements can be changed. It doesn't matter what you leave beyond the new length.
- Input: [3,2,2,3]
- Output: 2
- Assumptions:
- Do not allocate extra space for another array, you must do this in place with constant memory.
- Solution:
- 考的就是最基本的數(shù)組in-place去除元素, 關鍵在于注釋了remove the duplicate的那個if判斷
- Code:
# code block public int removeElement(int[] nums, int val) { if (nums == null || nums.length == 0) { return 0; } int idx = 0; for (int i = 0; i < nums.length; i++) { // remove duplicates if (nums[i] == val) { continue; } nums[idx++] = nums[i]; } return idx; }
- Time Complexity: O(n)
- Space Complexity: O(1)
<center>#28 Implement strStr()</center>
- link
- Description:
- Implement strStr().
- Returns the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
- Input: "asdf" "sd"
- Output: 1
- Assumptions:
- 有個更優(yōu)的算法叫KMP算法蒙揣,此處不做介紹靶溜,有興趣研究可以谷歌或百度
- Solution:
- 簡單的兩重循環(huán)鸣奔,注意corner case
- Code:
# code block public int strStr(String haystack, String needle) { if (haystack == null || needle == null) { return -1; } if (needle.length() == 0) { return 0; } if (haystack.length() == 0) { return -1; } for (int i = 0; i < haystack.length() - needle.length() + 1; i++) { boolean flag = true; for (int j = 0; j < needle.length() && j + i < haystack.length(); j++) { if (needle.charAt(j) != haystack.charAt(j + i)) { flag = false; break; } } if (flag) { return i; } } return -1; }
- Time Complexity: O(n ^ 2)
- Space Complexity: O(1)
<center>#29 Divide Two Integers</center>
- link
- Description:
- Divide two integers without using multiplication, division and mod operator.
- If it is overflow, return MAX_INT.
- Input: 123121 67
- Output: 1837
- Solution:
- 求商不能使用除墨技,余還有乘操作,那么思路一般就是使用位運算
- brute force的方法是累加divisor絕對值直到大于dividend
- 但是使用位運算挎狸,左移一位就是兩倍扣汪,這題可以用對divisor移位來簡化復雜度,從n的數(shù)量級到lg n
- 這題的難點在于對每一個細節(jié)的處理锨匆,正負崭别,溢出等等,包括考到正負數(shù)最大值的絕對值差1
- Code:
# code block public int divide(int dividend, int divisor) { if (divisor == 0) { return Integer.MAX_VALUE; } boolean isPos = true; if ((dividend < 0 && divisor > 0) || (dividend > 0 && divisor < 0)) { isPos = false; } long dividendL = Math.abs((long)dividend); long divisorL = Math.abs((long)divisor); if (dividendL < divisorL) { return 0; } long factor = 1; long cmp = divisorL; long result = 0; while ((cmp << 1) <= dividendL) { cmp <<= 1; factor <<= 1; } while (factor > 0 && dividendL > 0) { if (dividendL >= cmp) { result += factor; dividendL -= cmp; } factor >>= 1; cmp >>= 1; } if (isPos) { return (result < Integer.MAX_VALUE) ? (int)result : Integer.MAX_VALUE; } else { return (-result > Integer.MIN_VALUE) ? (int)-result : Integer.MIN_VALUE; } }
- Time Complexity: O(lg n)
- Space Complexity: O(1)
<center>#31 Next Permutation</center>
- link
- Description:
- Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.
- If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).
- The replacement must be in-place, do not allocate extra memory.
- Input: 1,2,3
- Output: 1,3,2
- Solution:
- permutation中比較難的題恐锣, 這題先將排列的樹畫出來茅主,找規(guī)律
- A_NEXT一定與A有盡可能長的公共前綴。
- 如果元素從底向上一直處于遞增土榴,說明是對這些元素來說诀姚,是沒有下一個排列的
- 從后向前比較相鄰的兩個元素,直到前一個元素小于后一個元素玷禽,停止赫段,這樣確保A_NEXT 與A有最長的公共前綴
- 下一步是找交換的點,必然是找從底部開始第一個大于停止的那個元素進行交換矢赁,能確保最小
- 如果從低到根都是遞增糯笙,那么下一個元素就是reverse整個數(shù)組
- 文字解釋有些難以理解,實際情況用實例將全排列的樹畫出來就能理解
- Code:
# code block public void nextPermutation(int[] nums) { if (nums == null || nums.length == 0) { return; } for (int i = nums.length - 2; i >= 0; i--) { if (nums[i] >= nums[i + 1]) { continue; } for (int j = nums.length - 1; j > i; j--) { if (nums[j] > nums[i]) { swap(nums, i, j); reverse(nums, i + 1, nums.length - 1); return; } } } reverse(nums, 0, nums.length - 1); } private void swap(int[] nums, int i, int j) { int tmp = nums[i]; nums[i] = nums[j]; nums[j] = tmp; } private void reverse(int[] nums, int start, int end) { while (start < end) { swap(nums, start, end); start++; end--; } }
- Time Complexity: O(n)
- 看似是兩重循環(huán)嵌套一個reverse撩银,實際上第一個循環(huán)找到要交換的第一個點给涕,第二重循環(huán)找到要交換的第二個點,對兩點間進行reverse,實際是三個O(n)的操作
- Space Complexity: O(1)
<center>#33 Search in Rotated Sorted Array</center>
- link
- Description:
- Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
- (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
- You are given a target value to search. If found in the array return its index, otherwise return -1.
- Input: 4 5 6 7 0 1 2, 5
- Output: 2
- Assumptions:
- You may assume no duplicate exists in the array.
- Solution:
- 排序非重復rotated數(shù)組够庙,滿足二分條件
- 本題難點在于分情況討論
- Code:
# code block public int search(int[] nums, int target) { if (nums == null || nums.length == 0) { return -1; } int start = 0, end = nums.length - 1; while (start < end - 1) { int mid = start + (end - start) / 2; if (nums[mid] == target) { return mid; } if (nums[start] < nums[end]) { // mono increasing if (nums[mid] < target) { start = mid; } else { end = mid; } } else if (nums[mid] <= nums[end]) { if (nums[mid] < target && nums[end] >= target) { start = mid; } else { end = mid; } } else { if (nums[mid] > target && nums[start] <= target) { end = mid; } else { start = mid; } } } if (nums[start] == target) { return start; } if (nums[end] == target) { return end; } return -1; }
- Time Complexity: O(lg n)
- Space Complexity: O(1)
<center>#34 Search for a Range</center>
- link
- Description:
- Given an array of integers sorted in ascending order, find the starting and ending position of a given target value.
- Your algorithm's runtime complexity must be in the order of O(log n).
- Input: [5, 7, 7, 8, 8, 10] and target value 8
- Output: [3, 4]
- Assumptions:
- If the target is not found in the array, return [-1, -1]
- Solution:
- 使用兩次二分分別找target第一次出現(xiàn)的索引和最后一次出現(xiàn)的索引恭应。
- 使用兩次二分是由于worst case 整個數(shù)組都是target, 兩次二分能保證O(lg n)的復雜度耘眨。
- Code:
# code block public int[] searchRange(int[] nums, int target) { int[] result = new int[2]; if (nums == null || nums.length == 0) { result[0] = -1; result[1] = -1; return result; } int start = 0, end = nums.length - 1; // find the first occurence of target while (start < end - 1) { int mid = start + (end - start) / 2; if (nums[mid] >= target) { end = mid; } else { start = mid; } } if (nums[start] == target) { result[0] = start; } else if (nums[end] == target) { result[0] = end; } else { result[0] = -1; result[1] = -1; return result; } start = 0; end = nums.length - 1; // find the last occurence of target while (start < end - 1) { int mid = start + (end - start) / 2; if (nums[mid] <= target) { start = mid; } else { end = mid; } } if (nums[end] == target) { result[1] = end; } else { result[1] = start; } return result; }
- Time Complexity: O(lg n)
- Space Complexity: O(1)
<center>#35 Search Insert Position</center>
-
Description:
- Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
Input: [1,3,5,6], 5
Output: 2
-
Assumptions:
- assume no duplicates in the array.
-
Solution:
- 搜索排序數(shù)組就要想到二分法暮屡。 這題要找的是第一個>= target的索引。
- 注意點:
- 使用start < end - 1 是防止棧溢出毅桃, 如果start = end - 1的話mid就會是start,如果nums[mid] < target就會陷入死循環(huán)
- 從循環(huán)跳出會有兩種情況准夷, start == end 或 start == end - 1钥飞。 所以對start和end進行分別處理。
-
Code:
# code block public int searchInsert(int[] nums, int target) { if (nums == null || nums.length == 0) { return 0; } int start = 0, end = nums.length - 1; while (start < end - 1) { int mid = start + (end - start) / 2; if (nums[mid] >= target) { end = mid; } else { start = mid; } } if (nums[start] >= target) { return start; } else if (nums[end] >= target) { return end; } else { // the target is greater than all the numbers in the array return end + 1; } }
Time Complexity: O(lg n)
Space Complexity: O(1)
<center>#36 Valid Sudoku</center>
- link
- Description:
- Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules.
- The Sudoku board could be partially filled, where empty cells are filled with the character '.'.
- Input:
- Output:
- Assumptions:
- A valid Sudoku board (partially filled) is not necessarily solvable. Only the filled cells need to be validated.
- Solution:
- 注意邏輯要分離
- Code:
# code block public boolean isValidSudoku(char[][] board) { return checkRow(board) && checkColumn(board) && checkGrids(board); } private boolean checkRow(char[][] board) { for (int i = 0; i < 9; i++) { boolean[] visit = new boolean[10]; for (int j = 0; j < 9; j++) { if (board[i][j] == '.') { continue; } if (visit[board[i][j] - '0']) { return false; } visit[board[i][j] - '0'] = true; } } return true; } private boolean checkColumn(char[][] board) { for (int j = 0; j < 9; j++) { boolean[] visit = new boolean[10]; for (int i = 0; i < 9; i++) { if (board[i][j] == '.') { continue; } if (visit[board[i][j] - '0']) { return false; } visit[board[i][j] - '0'] = true; } } return true; } private boolean checkGrids(char[][] board) { for (int i = 0; i < 9; i += 3) { for (int j = 0; j < 9; j += 3) { if (!checkGrid(board, i, j)) { return false; } } } return true; } private boolean checkGrid(char[][] board, int x, int y) { boolean[] visit = new boolean[10]; for (int i = x; i < x + 3; i++) { for (int j = y; j < y + 3; j++) { if (board[i][j] == '.') { continue; } if (visit[board[i][j] - '0']) { return false; } visit[board[i][j] - '0'] = true; } } return true; }
- Time Complexity: O(n ^ 2)
- Space Complexity: O(n ^ 2)
<center>#38 Count and Say</center>
- link
- Description:
- The count-and-say sequence is the sequence of integers with the first five terms as following:
- 1 is read off as "one 1" or 11.
- 11 is read off as "two 1s" or 21.
- 21 is read off as "one 2, then one 1" or 1211.
- Given an integer n, generate the nth term of the count-and-say sequence.
- Note: Each term of the sequence of integers will be represented as a string.
- Input: 4
- Output: "1211"
- Solution:
- 模擬題衫嵌,按照題目的原意模擬過程
- 注意corner case读宙,比如1的時候
- Code:
# code block public String countAndSay(int n) { String result = "1"; for (int i = 2; i <= n; i++) { result = countAndSay(result); } return result; } private String countAndSay(String str) { int count = 1; char say = str.charAt(0); StringBuilder sb = new StringBuilder(); for (int i = 1; i < str.length(); i++) { if (str.charAt(i) == say) { count++; continue; } else { sb.append(count); sb.append(say); count = 1; say = str.charAt(i); } } sb.append(count); sb.append(say); return sb.toString(); }
<center>#39 Combination Sum</center>
-
Description:
- Given a set of candidate numbers (C) (without duplicates) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
- The same repeated number may be chosen from C unlimited number of times.
Input: [2, 3, 6, 7]
Output: [[7], [2, 2, 3]]
-
Assumptions:
- without duplicates
- All numbers (including target) will be positive integers.
- without duplicates
-
Solution:
- 組合的題, 不包含重復數(shù)字楔绞,可以把組合當做一個隱式圖结闸, 用DFS對隱式圖進行遍歷。首先排序酒朵,因為排完序之后方便去重桦锄, 還方便對樹進行剪枝。假如第i個數(shù)已經(jīng)大于目標蔫耽,那后面的數(shù)一定也大于目標结耀,不在答案中。
- 注意點:
- 每找到一個答案要進行deepcopy匙铡,因為dfs中用到了回溯图甜,state數(shù)組會一直變化。
-
Code:
# code block public List<List<Integer>> combinationSum(int[] candidates, int target) { List<List<Integer>> result = new ArrayList<>(); if (candidates == null || candidates.length == 0) { return result; } Arrays.sort(candidates); dfsHelper(candidates, target, 0, new ArrayList<Integer>(), result); return result; } private void dfsHelper(int[] nums, int target, int start, List<Integer> state, List<List<Integer>> result) { if (target == 0) { result.add(new ArrayList<Integer>(state)); return; } for (int i = start; i < nums.length; i++) { // 剪枝 if (nums[i] > target) { break; } state.add(nums[i]); // start from i because every number can be used for multiple times. dfsHelper(nums, target - nums[i], i, state, result); // backtracking state.remove(state.size() - 1); } }
<center>#40 Combination Sum II</center>
-
Description:
- Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
Input: [10, 1, 2, 7, 6, 1, 5] and target 8
Output: [[1, 7], [1, 2, 5], [2, 6], [1, 1, 6]]
-
Assumptions:
- All numbers (including target) will be positive integers.
- The solution set must not contain duplicate combinations
- All numbers (including target) will be positive integers.
-
Solution:
- 求組合的題鳖眼, 可重復數(shù)字黑毅,并且數(shù)組中每個數(shù)字只能用一次,可以把組合當做一個隱式圖钦讳, 用DFS對隱式圖進行遍歷矿瘦。首先排序,因為排完序之后方便去重蜂厅, 還方便對樹進行剪枝匪凡。假如第i個數(shù)已經(jīng)大于目標,那后面的數(shù)一定也大于目標掘猿,不在答案中病游。
- 注意點:
- 每找到一個答案要進行deepcopy,因為dfs中用到了回溯,state數(shù)組會一直變化衬衬。
- 去重方法用remove duplicate注釋了
- 每找到一個答案要進行deepcopy,因為dfs中用到了回溯,state數(shù)組會一直變化衬衬。
-
Code:
# code block public List<List<Integer>> combinationSum2(int[] candidates, int target) { List<List<Integer>> result = new ArrayList<>(); if (candidates == null || candidates.length == 0) { return result; } Arrays.sort(candidates); dfsHelper(candidates, target, 0, new ArrayList<Integer>(), result); return result; } private void dfsHelper(int[] candidates, int target, int start, List<Integer> state, List<List<Integer>> result) { if (target == 0) { result.add(new ArrayList<Integer>(state)); return; } for (int i = start; i < candidates.length; i++) { if (candidates[i] > target) { break; } // remove duplicates if (i != start && candidates[i] == candidates[i - 1]) { continue; } state.add(candidates[i]); dfsHelper(candidates, target - candidates[i], i + 1, state, result); state.remove(state.size() - 1); } }
<center>#43 Multiply Strings</center>
- link
- Description:
- Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2.
- The length of both num1 and num2 is < 110.
- Both num1 and num2 contains only digits 0-9.
- Both num1 and num2 does not contain any leading zero.
- You must not use any built-in BigInteger library or convert the inputs to integer directly.
- Input: "123", "456"
- Output: "56088"
- Solution:
- 暴力方法是直接模擬乘法計算
- 比較優(yōu)雅的方法可以參考下圖
- [圖片上傳失敗...(image-4f2751-1534568626309)]
- 注意點:主要處理trailing zeroes
- Code:
# code block public String multiply(String num1, String num2) { if (num1.equals("0") || num2.equals("0")) { return "0"; } int l1 = num1.length(); int l2 = num2.length(); int[] result = new int[l1 + l2]; for (int i = l1 - 1; i >= 0; i--) { for (int j = l2 - 1; j >= 0; j--) { int val = (num1.charAt(i) - '0') * (num2.charAt(j) - '0'); int sum = result[i + j + 1] + val; result[i + j] += sum / 10; result[i + j + 1] = sum % 10; } } StringBuilder sb = new StringBuilder(); for (int i = 0; i < result.length; i++) { if (sb.length() == 0 && result[i] == 0) { continue; } sb.append(result[i]); } return sb.length() == 0 ? "0" : sb.toString(); }
- Time Complexity: O(m * n)
- Space Complexity: O(m * n)
<center>#46 Permutations</center>
- link
- Description:
- Given a collection of distinct numbers, return all possible permutations.
- Input:[1,2,3]
- Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
- Solution:
- 與排列相比較买猖,需要多一個Set來記錄當前狀態(tài)的值的索引
- 回溯的時候注意不僅要回溯當前狀態(tài),也需要回溯Set的值
- 因為是distinct numbers滋尉, 所以不需要去重
- Code:
# code block public List<List<Integer>> permute(int[] nums) { List<List<Integer>> result = new ArrayList<>(); if (nums == null || nums.length == 0) { return result; } dfsHelper(nums, new HashSet<Integer>(), new ArrayList<Integer>(), result); return result; } private void dfsHelper(int[] nums, Set<Integer> set, List<Integer> state, List<List<Integer>> result) { if (nums.length == set.size()) { result.add(new ArrayList<Integer>(state)); return; } for (int i = 0; i < nums.length; i++) { if (!set.contains(i)) { set.add(i); state.add(nums[i]); dfsHelper(nums, set, state, result); // backtracking state.remove(state.size() - 1); set.remove(i); } } }
<center>#47 Permutations II</center>
- link
- Description:
- Given a collection of numbers that might contain duplicates, return all possible unique permutations.
- Input: [1,1,2]
- Output: [[1,1,2],[1,2,1],[2,1,1]]
- Solution:
- Permutation 的 follow up玉控,經(jīng)典的去重題
- 與combination一樣,要選代表狮惜,不同的就是combination是通過start記錄歷史高诺,而permutation是使用set
- 去重第一個要想到排序
- 去重的部分使用注釋標識了
- Code:
# code block public List<List<Integer>> permuteUnique(int[] nums) { List<List<Integer>> result = new ArrayList<>(); if (nums == null || nums.length == 0) { return result; } Arrays.sort(nums); dfsHelper(nums, new HashSet<Integer>(), new ArrayList<Integer>(), result); return result; } private void dfsHelper(int[] nums, Set<Integer> set, List<Integer> state, List<List<Integer>> result) { if (nums.length == set.size()) { result.add(new ArrayList<Integer>(state)); return; } for (int i = 0; i < nums.length; i++) { // remove duplicate if (set.contains(i)) { continue; } // if nums[i] equals to nums[i - 1], then nums[i - 1] must be in the permutation // this is the strategy for removing duplicates if (i != 0 && nums[i] == nums[i - 1] && !set.contains(i - 1)) { continue; } state.add(nums[i]); set.add(i); dfsHelper(nums, set, state, result); // backtracking set.remove(i); state.remove(state.size() - 1); } }
<center>#48 Rotate Image</center>
- link
- Description:
- You are given an n x n 2D matrix representing an image.
- Rotate the image by 90 degrees (clockwise).
- You have to rotate the image in-place, which means you have to modify the input 2D matrix directly.
- DO NOT allocate another 2D matrix and do the rotation.
- Input:
[ [1,2,3], [4,5,6], [7,8,9] ],
- Output:
[ [7,4,1], [8,5,2], [9,6,3] ]
- Solution:
- 這其實更像是找規(guī)律的題
- 解法一:沿對角線翻轉,按行reverse
- 解法二:通過尋找規(guī)律可以發(fā)現(xiàn)碾篡,swap三次可以使沿中心對稱的四個點到達最終位置虱而,所以可以一圈一圈的轉換。One Pass开泽。
- Code:
# code block 解法一: public void rotate(int[][] matrix) { if (matrix == null || matrix.length <= 1) { return; } int n = matrix.length; for (int i = 1; i < n; i++) { for (int j = 0; j < i; j++) { swap(matrix, i, j, j, i); } } for (int i = 0; i < n; i++) { reverse(matrix, i); } } private void reverse(int[][] matrix, int x) { int start = 0, end = matrix[x].length - 1; while (start < end) { int tmp = matrix[x][start]; matrix[x][start] = matrix[x][end]; matrix[x][end] = tmp; start++; end--; } } private void swap(int[][] matrix, int x1, int y1, int x2, int y2) { int tmp = matrix[x1][y1]; matrix[x1][y1] = matrix[x2][y2]; matrix[x2][y2] = tmp; } 解法二: public void rotate(int[][] matrix) { if (matrix == null || matrix.length <= 1) { return; } int n = matrix.length; int start = 0, end = n - 1; while (start < end) { for (int i = start; i < end; i++) { swap(matrix, start, i, i, end); swap(matrix, start, i, end, end - i); swap(matrix, start, i, end - i, start); } start++; end--; } } private void swap(int[][] matrix, int x1, int y1, int x2, int y2) { int tmp = matrix[x1][y1]; matrix[x1][y1] = matrix[x2][y2]; matrix[x2][y2] = tmp; }
- Time Complexity: O(n ^ 2)
- Space Complexity: O(1)
<center>#49 Group Anagrams</center>
- link
- Description:
- Given an array of strings, group anagrams together.
- Input: ["eat","tea","tan","ate","nat","bat"]
- Output: [["bat"],["ate","eat","tea"],["nat","tan"]]
- Solution:
- 這題考察的是哈希表的應用牡拇,以及對anagram的理解
- 通過對每一個string的char數(shù)組排序作為key,每一組anagram都有同一個key穆律,使用hashmap做收集
- 更優(yōu)的解法是自己寫不重復的hash function惠呼,可以參考網(wǎng)上的質(zhì)數(shù)解法
- Code:
# code block public List<List<String>> groupAnagrams(String[] strs) { List<List<String>> result = new ArrayList<>(); if (strs == null || strs.length == 0) { return result; } Map<String, List<String>> map = new HashMap<>(); for (String s : strs) { char[] sc = s.toCharArray(); Arrays.sort(sc); String key = new String(sc); if (!map.containsKey(key)) { map.put(key, new ArrayList<String>()); } map.get(key).add(s); } for (String key : map.keySet()) { result.add(map.get(key)); } return result; }
- Time Complexity: O(n * lg(length))
- Space Complexity: O(n * length)