auto commit

This commit is contained in:
CyC2018 2018-04-04 17:54:29 +08:00
parent 1108000de1
commit dc7b893291

View File

@ -421,7 +421,7 @@ public int[][] reconstructQueue(int[][] people) {
双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。
**从一个已经排序的数组中找出两个数,使它们的和为 0**
**有序数组的 Tow Sum**
[Leetcode 167. Two Sum II - Input array is sorted (Easy)](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/description/)
@ -430,6 +430,8 @@ Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2
```
题目描述:从一个已经排序的数组中找出两个数,使它们的和为 0。
使用双指针,一个指针指向元素较小的值,一个指针指向元素较大的值。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。
如果两个指针指向元素的和 sum == target那么得到要求的结果如果 sum > target移动较大的元素使 sum 变小一些;如果 sum < target移动较小的元素使 sum 变大一些
@ -458,22 +460,22 @@ Given s = "leetcode", return "leotcede".
使用双指针,指向待反转的两个元音字符,一个指针从头向尾遍历,一个指针从尾到头遍历。
```java
private HashSet<Character> vowels = new HashSet<>(Arrays.asList('a','e','i','o','u','A','E','I','O','U'));
private HashSet<Character> vowels = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));
public String reverseVowels(String s) {
if(s.length() == 0) return s;
if (s.length() == 0) return s;
int i = 0, j = s.length() - 1;
char[] result = new char[s.length()];
while(i <= j){
while (i <= j) {
char ci = s.charAt(i);
char cj = s.charAt(j);
if(!vowels.contains(ci)){
if (!vowels.contains(ci)) {
result[i] = ci;
i++;
} else if(!vowels.contains(cj)){
} else if (!vowels.contains(cj)) {
result[j] = cj;
j--;
} else{
} else {
result[i] = cj;
result[j] = ci;
i++;
@ -498,12 +500,12 @@ Explanation: 1 * 1 + 2 * 2 = 5
```java
public boolean judgeSquareSum(int c) {
int left = 0, right = (int) Math.sqrt(c);
while(left <= right){
int powSum = left * left + right * right;
if(powSum == c) return true;
else if(powSum > c) right--;
else left++;
int i = 0, j = (int) Math.sqrt(c);
while (i <= j) {
int powSum = i * i + j * j;
if (powSum == c) return true;
if (powSum > c) j--;
else i++;
}
return false;
}
@ -523,9 +525,9 @@ Explanation: You could delete the character 'c'.
```java
public boolean validPalindrome(String s) {
int i = 0, j = s.length() -1;
while(i < j){
if(s.charAt(i) != s.charAt(j)){
int i = 0, j = s.length() - 1;
while (i < j) {
if (s.charAt(i) != s.charAt(j)) {
return isPalindrome(s, i, j - 1) || isPalindrome(s, i + 1, j);
}
i++;
@ -534,12 +536,9 @@ public boolean validPalindrome(String s) {
return true;
}
private boolean isPalindrome(String s, int l, int r){
while(l < r){
if(s.charAt(l) != s.charAt(r))
return false;
l++;
r--;
private boolean isPalindrome(String s, int l, int r) {
while (l < r) {
if (s.charAt(l++) != s.charAt(r--)) return false;
}
return true;
}
@ -554,13 +553,13 @@ private boolean isPalindrome(String s, int l, int r){
```java
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i = m - 1, j = n - 1; // 需要从尾开始遍历,否则在 nums1 上归并得到的值会覆盖还未进行归并比较的值
int idx = m + n - 1;
while(i >= 0 || j >= 0){
if(i < 0) nums1[idx] = nums2[j--];
else if(j < 0) nums1[idx] = nums1[i--];
else if(nums1[i] > nums2[j]) nums1[idx] = nums1[i--];
else nums1[idx] = nums2[j--];
idx--;
int index = m + n - 1;
while (i >= 0 || j >= 0) {
if (i < 0) nums1[index] = nums2[j--];
else if (j < 0) nums1[index] = nums1[i--];
else if (nums1[i] > nums2[j]) nums1[index] = nums1[i--];
else nums1[index] = nums2[j--];
index--;
}
}
```
@ -573,12 +572,12 @@ public void merge(int[] nums1, int m, int[] nums2, int n) {
```java
public boolean hasCycle(ListNode head) {
if(head == null) return false;
if (head == null) return false;
ListNode l1 = head, l2 = head.next;
while(l1 != null && l2 != null){
if(l1 == l2) return true;
while (l1 != null && l2 != null) {
if (l1 == l2) return true;
l1 = l1.next;
if(l2.next == null) break;
if (l2.next == null) break;
l2 = l2.next.next;
}
return false;
@ -606,8 +605,7 @@ public String findLongestWord(String s, List<String> d) {
for (int i = 0, j = 0; i < s.length() && j < str.length(); i++) {
if (s.charAt(i) == str.charAt(j)) j++;
if (j == str.length()) {
if (ret.length() < str.length()
|| (ret.length() == str.length() && ret.compareTo(str) > 0)) {
if (ret.length() < str.length() || (ret.length() == str.length() && ret.compareTo(str) > 0)) {
ret = str;
}
}
@ -621,9 +619,9 @@ public String findLongestWord(String s, List<String> d) {
### 快速选择
一般用于求解 **Kth Element** 问题,可以在 O(n) 时间复杂度O(1) 空间复杂度完成求解工作。
一般用于求解 **Kth Element** 问题,可以在 O(N) 时间复杂度O(1) 空间复杂度完成求解工作。
与快速排序一样,快速选择一般需要先打乱数组,否则最坏情况下时间复杂度为 O(n<sup>2</sup>)。
与快速排序一样,快速选择一般需要先打乱数组,否则最坏情况下时间复杂度为 O(N<sup>2</sup>)。
### 堆排序
@ -633,24 +631,23 @@ public String findLongestWord(String s, List<String> d) {
[Leetocde : 215. Kth Largest Element in an Array (Medium)](https://leetcode.com/problems/kth-largest-element-in-an-array/description/)
**排序** :时间复杂度 O(nlgn),空间复杂度 O(1)
**排序** :时间复杂度 O(NlogN),空间复杂度 O(1)
```java
public int findKthLargest(int[] nums, int k) {
int N = nums.length;
Arrays.sort(nums);
return nums[N - k];
Arrays.sort(nums);
return nums[nums.length - k];
}
```
**堆排序** :时间复杂度 O(nlgk),空间复杂度 O(k)
**堆排序** :时间复杂度 O(OlogK),空间复杂度 O(K)。
```java
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> pq = new PriorityQueue<>();
for(int val : nums) {
pq.offer(val);
if(pq.size() > k) {
for (int val : nums) {
pq.add(val);
if (pq.size() > k) {
pq.poll();
}
}
@ -658,50 +655,41 @@ public int findKthLargest(int[] nums, int k) {
}
```
**快速选择** :时间复杂度 O(n),空间复杂度 O(1)
**快速选择** :时间复杂度 O(N),空间复杂度 O(1)
```java
public int findKthLargest(int[] nums, int k) {
k = nums.length - k;
int lo = 0;
int hi = nums.length - 1;
while (lo < hi) {
final int j = partition(nums, lo, hi);
if(j < k) {
lo = j + 1;
} else if (j > k) {
hi = j - 1;
} else {
break;
}
}
return nums[k];
k = nums.length - k;
int l = 0, h = nums.length - 1;
while (l < h) {
int j = partition(nums, l, h);
if (j == k) break;
if (j < k) l = j + 1;
else h = j - 1;
}
return nums[k];
}
private int partition(int[] a, int lo, int hi) {
int i = lo;
int j = hi + 1;
while(true) {
while(i < hi && less(a[++i], a[lo]));
while(j > lo && less(a[lo], a[--j]));
if(i >= j) {
break;
}
exch(a, i, j);
}
exch(a, lo, j);
return j;
private int partition(int[] a, int l, int h) {
int i = l, j = h + 1;
while (true) {
while (i < h && less(a[++i], a[l])) ;
while (j > l && less(a[l], a[--j])) ;
if (i >= j) break;
swap(a, i, j);
}
swap(a, l, j);
return j;
}
private void exch(int[] a, int i, int j) {
final int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
private void swap(int[] a, int i, int j) {
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
private boolean less(int v, int w) {
return v < w;
}
private boolean less(int v, int w) {
return v < w;
}
```
@ -720,21 +708,21 @@ Given [1,1,1,2,2,3] and k = 2, return [1,2].
```java
public List<Integer> topKFrequent(int[] nums, int k) {
List<Integer> ret = new ArrayList<>();
Map<Integer, Integer> map = new HashMap<>();
for(int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
Map<Integer, Integer> frequencyMap = new HashMap<>();
for (int num : nums) {
frequencyMap.put(num, frequencyMap.getOrDefault(num, 0) + 1);
}
List<Integer>[] bucket = new List[nums.length + 1];
for(int key : map.keySet()) {
int frequency = map.get(key);
if(bucket[frequency] == null) {
for (int key : frequencyMap.keySet()) {
int frequency = frequencyMap.get(key);
if (bucket[frequency] == null) {
bucket[frequency] = new ArrayList<>();
}
bucket[frequency].add(key);
}
for(int i = bucket.length - 1; i >= 0 && ret.size() < k; i--) {
if(bucket[i] != null) {
for (int i = bucket.length - 1; i >= 0 && ret.size() < k; i--) {
if (bucket[i] != null) {
ret.addAll(bucket[i]);
}
}
@ -820,7 +808,7 @@ private class Position {
<div align="center"> <img src="../pics//f7f7e3e5-7dd4-4173-9999-576b9e2ac0a2.png"/> </div><br>
广度优先搜索一层一层遍历,每一层得到的所有新节点,要用队列先存储起来以备下一层遍历的时候再遍历;而深度优先搜索在得到到一个新节点时立马对新节点进行遍历:从节点 0 出发开始遍历,得到到新节点 6 时,立马对新节点 6 进行遍历,得到新节点 4如此反复以这种方式遍历新节点直到没有新节点了此时返回。返回到根节点 0 的情况是,继续对根节点 0 进行遍历,得到新节点 2然后继续以上步骤。
广度优先搜索一层一层遍历,每一层得到的所有新节点,要用队列先存储起来以备下一层遍历的时候再遍历;而深度优先搜索在得到到一个新节点时立马对新节点进行遍历:从节点 0 出发开始遍历,得到到新节点 6 时,立马对新节点 6 进行遍历,得到新节点 4如此反复以这种方式遍历新节点直到没有新节点了此时返回。返回到根节点 0 的情况是,继续对根节点 0 进行遍历,得到新节点 2然后继续以上步骤。
从一个节点出发,使用 DFS 对一个图进行遍历时能够遍历到的节点都是从初始节点可达的DFS 常用来求解这种 **可达性** 问题。
@ -846,20 +834,21 @@ private class Position {
```java
public int maxAreaOfIsland(int[][] grid) {
int m = grid.length, n = grid[0].length;
int max = 0;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(grid[i][j] == 1) max = Math.max(max, dfs(grid, i, j));
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == 1) {
max = Math.max(max, dfs(grid, i, j));
}
}
}
return max;
}
private int dfs(int[][] grid, int i, int j){
int m = grid.length, n = grid[0].length;
if(i < 0 || i >= m || j < 0 || j >= n) return 0;
if(grid[i][j] == 0) return 0;
private int dfs(int[][] grid, int i, int j) {
if (i < 0 || i >= grid.length || j < 0 || j >= grid[i].length || grid[i][j] == 0) {
return 0;
}
grid[i][j] = 0;
return dfs(grid, i + 1, j) + dfs(grid, i - 1, j) + dfs(grid, i, j + 1) + dfs(grid, i, j - 1) + 1;
}
@ -883,22 +872,22 @@ The 2nd student himself is in a friend circle. So return 2.
public int findCircleNum(int[][] M) {
int n = M.length;
int ret = 0;
boolean[] hasFind = new boolean[n];
for(int i = 0; i < n; i++) {
if(!hasFind[i]) {
dfs(M, i, hasFind);
boolean[] hasVisited = new boolean[n];
for (int i = 0; i < n; i++) {
if (!hasVisited[i]) {
dfs(M, i, hasVisited);
ret++;
}
}
return ret;
}
private void dfs(int[][] M, int i, boolean[] hasFind) {
hasFind[i] = true;
int n = M.length;
for(int k = 0; k < n; k++) {
if(M[i][k] == 1 && !hasFind[k]) {
dfs(M, k, hasFind);
private void dfs(int[][] M, int i, boolean[] hasVisited) {
hasVisited[i] = true;
for (int k = 0; k < M.length; k++) {
if (M[i][k] == 1 && !hasVisited[k]) {
dfs(M, k, hasVisited);
}
}
}
@ -950,11 +939,11 @@ private void dfs(char[][] grid, int i, int j) {
[Leetcode : 257. Binary Tree Paths (Easy)](https://leetcode.com/problems/binary-tree-paths/description/)
```html
1
/ \
1
/ \
2 3
\
5
5
```
```html
["1->2->5", "1->3"]
@ -980,6 +969,41 @@ private void dfs(TreeNode root, String prefix, List<String> ret){
}
```
**IP 地址划分**
[Leetcode : 93. Restore IP Addresses(Medium)](https://leetcode.com/problems/restore-ip-addresses/description/)
```html
Given "25525511135",
return ["255.255.11.135", "255.255.111.35"].
```
```java
private List<String> ret;
public List<String> restoreIpAddresses(String s) {
ret = new ArrayList<>();
doRestore(0, "", s);
return ret;
}
private void doRestore(int k, String path, String s) {
if (k == 4 || s.length() == 0) {
if (k == 4 && s.length() == 0) {
ret.add(path);
}
return;
}
for (int i = 0; i < s.length() && i <= 2; i++) {
if (i != 0 && s.charAt(0) == '0') break;
String part = s.substring(0, i + 1);
if (Integer.valueOf(part) <= 255) {
doRestore(k + 1, path.length() != 0 ? path + "." + part : part, s.substring(i + 1));
}
}
}
```
**填充封闭区域**
[Leetcode : 130. Surrounded Regions (Medium)](https://leetcode.com/problems/surrounded-regions/description/)
@ -1102,7 +1126,7 @@ private void dfs(int r, int c, boolean[][] canReach) {
### Backtracking
回溯是 DFS 的一种,它不是用在遍历图的节点上,而是用于求解 **排列组合** 问题,例如有 { 'a','b','c' } 三个字符,求解所有由这三个字符排列得到的字符串。
回溯属于 DF,它不是用在遍历图的节点上,而是用于求解 **排列组合** 问题,例如有 { 'a','b','c' } 三个字符,求解所有由这三个字符排列得到的字符串。
在程序实现时,回溯需要注意对元素进行标记的问题。使用递归实现的回溯,在访问一个新元素进入新的递归调用时,需要将新元素标记为已经访问,这样才能在继续递归调用时不用重复访问该元素;但是在递归返回时,需要将该元素标记为未访问,因为只需要保证在一个递归链中不同时访问一个元素,可以访问已经访问过但是不在当前递归链中的元素。
@ -1122,20 +1146,21 @@ private static final String[] KEYS = {"", "", "abc", "def", "ghi", "jkl", "mno",
public List<String> letterCombinations(String digits) {
List<String> ret = new ArrayList<>();
if (digits != null && digits.length() != 0) {
combination("", digits, 0, ret);
}
if (digits == null || digits.length() == 0) return ret;
combination(new StringBuilder(), digits, ret);
return ret;
}
private void combination(String prefix, String digits, int offset, List<String> ret) {
if (offset == digits.length()) {
ret.add(prefix);
private void combination(StringBuilder prefix, String digits, List<String> ret) {
if (prefix.length() == digits.length()) {
ret.add(prefix.toString());
return;
}
String letters = KEYS[digits.charAt(offset) - '0'];
String letters = KEYS[digits.charAt(prefix.length()) - '0'];
for (char c : letters.toCharArray()) {
combination(prefix + c, digits, offset + 1, ret);
prefix.append(c);
combination(prefix, digits, ret);
prefix.deleteCharAt(prefix.length() - 1); // 删除
}
}
```
@ -1181,55 +1206,22 @@ private boolean dfs(char[][] board, String word, int start, int r, int c) {
if (start == word.length()) {
return true;
}
if (r < 0 || r >= m || c < 0 || c >= n || board[r][c] != word.charAt(start) || visited[r][c] ) {
if (r < 0 || r >= m || c < 0 || c >= n || board[r][c] != word.charAt(start) || visited[r][c]) {
return false;
}
visited[r][c] = true;
for (int i = 0; i < shift.length; i++) {
int nextR = r + shift[i][0];
int nextC = c + shift[i][1];
if (dfs(board, word, start + 1, nextR, nextC)) return true;
if (dfs(board, word, start + 1, nextR, nextC)) {
return true;
}
}
visited[r][c] = false;
return false;
}
```
**IP 地址划分**
[Leetcode : 93. Restore IP Addresses(Medium)](https://leetcode.com/problems/restore-ip-addresses/description/)
```html
Given "25525511135",
return ["255.255.11.135", "255.255.111.35"].
```
```java
private List<String> ret;
public List<String> restoreIpAddresses(String s) {
ret = new ArrayList<>();
doRestore(0, "", s);
return ret;
}
private void doRestore(int k, String path, String s) {
if (k == 4 || s.length() == 0) {
if (k == 4 && s.length() == 0) {
ret.add(path);
}
return;
}
for (int i = 0; i < s.length() && i <= 2; i++) {
if (i != 0 && s.charAt(0) == '0') break;
String part = s.substring(0, i + 1);
if (Integer.valueOf(part) <= 255) {
doRestore(k + 1, path.length() != 0 ? path + "." + part : part, s.substring(i + 1));
}
}
}
```
**排列**
[Leetcode : 46. Permutations (Medium)](https://leetcode.com/problems/permutations/description/)
@ -1297,12 +1289,12 @@ public List<List<Integer>> permuteUnique(int[] nums) {
private void backtracking(List<Integer> permuteList, boolean[] visited, int[] nums, List<List<Integer>> ret) {
if (permuteList.size() == nums.length) {
ret.add(new ArrayList(permuteList));
ret.add(new ArrayList(permuteList)); // 重新构造一个 List
return;
}
for (int i = 0; i < visited.length; i++) {
if (i != 0 && nums[i] == nums[i - 1] && !visited[i - 1]) continue;
if (i != 0 && nums[i] == nums[i - 1] && !visited[i - 1]) continue; // 防止重复
if (visited[i]) continue;
visited[i] = true;
permuteList.add(nums[i]);
@ -1339,7 +1331,7 @@ public List<List<Integer>> combine(int n, int k) {
private void backtracking(int start, int n, int k, List<Integer> combineList, List<List<Integer>> ret){
if(k == 0){
ret.add(new ArrayList(combineList)); // 这里要重新构造一个 List
ret.add(new ArrayList(combineList));
return;
}
@ -1441,7 +1433,7 @@ private List<Integer> subsetList;
public List<List<Integer>> subsets(int[] nums) {
ret = new ArrayList<>();
subsetList = new ArrayList<>();
for (int i = 0; i <= nums.length; i++) {
for (int i = 0; i <= nums.length; i++) { // 不同的子集大小
backtracking(0, i, nums);
}
return ret;
@ -3079,7 +3071,7 @@ public int majorityElement(int[] nums) {
}
```
可以利用 Boyer-Moore Majority Vote Algorithm 来解决这个问题,使得时间复杂度为 O(n)。可以这么理解该算法:使用 cnt 来统计一个元素出现的次数,当遍历到的元素和统计元素不等时,令 cnt--。如果前面查找了 i 个元素,且 cnt == 0 ,说明前 i 个元素没有 majority或者有 majority但是出现的次数少于 i / 2 ,因为如果多于 i / 2 的话 cnt 就一定不会为 0 。此时剩下的 n - i 个元素中majority 的数目依然多于 (n - i) / 2因此继续查找就能找出 majority。
可以利用 Boyer-Moore Majority Vote Algorithm 来解决这个问题,使得时间复杂度为 O(n)。可以这么理解该算法:使用 cnt 来统计一个元素出现的次数,当遍历到的元素和统计元素不等时,令 cnt--。如果前面查找了 i 个元素,且 cnt == 0 ,说明前 i 个元素没有 majority或者有 majority但是出现的次数少于 i / 2 ,因为如果多于 i / 2 的话 cnt 就一定不会为 0 。此时剩下的 n - i 个元素中majority 的数目依然多于 (n - i) / 2因此继续查找就能找出 majority。
```java
public int majorityElement(int[] nums) {
@ -3185,11 +3177,13 @@ public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] ret = new int[n];
ret[0] = 1;
for(int i = 1; i < n; i++) {
ret[i] = ret[i - 1] * nums[i - 1];
int left = 1;
for (int i = 1; i < n; i++) {
ret[i] = left * nums[i - 1];
left *= nums[i - 1];
}
int right = 1;
for(int i = n - 1; i >= 0; i--) {
for (int i = n - 1; i >= 0; i--) {
ret[i] *= right;
right *= nums[i];
}
@ -3197,22 +3191,6 @@ public int[] productExceptSelf(int[] nums) {
}
```
**统计从 0 \~ n 每个数的二进制表示中 1 的个数**
[Leetcode : 338. Counting Bits (Medium)](https://leetcode.com/problems/counting-bits/description/)
对于数字 6(110),它可以看成是数字 (10) 前面加上一个 1 ,因此 dp[i] = dp[i&(i-1)] + 1;
```java
public int[] countBits(int num) {
int[] ret = new int[num + 1];
for(int i = 1; i <= num; i++){
ret[i] = ret[i&(i-1)] + 1;
}
return ret;
}
```
# 数据结构相关
## 栈和队列
@ -5470,6 +5448,22 @@ public int maxProduct(String[] words) {
}
```
**统计从 0 \~ n 每个数的二进制表示中 1 的个数**
[Leetcode : 338. Counting Bits (Medium)](https://leetcode.com/problems/counting-bits/description/)
对于数字 6(110),它可以看成是数字 (10) 前面加上一个 1 ,因此 dp[i] = dp[i&(i-1)] + 1;
```java
public int[] countBits(int num) {
int[] ret = new int[num + 1];
for(int i = 1; i <= num; i++){
ret[i] = ret[i&(i-1)] + 1;
}
return ret;
}
```
# 参考资料
- [Leetcode](https://leetcode.com/problemset/algorithms/?status=Todo)