auto commit

This commit is contained in:
CyC2018 2018-03-19 17:23:50 +08:00
parent da92069434
commit 1d80d9c7e8

View File

@ -57,6 +57,7 @@
* [48. 最长不含重复字符的子字符串](#48-最长不含重复字符的子字符串)
* [49. 丑数](#49-丑数)
* [50. 第一个只出现一次的字符位置](#50-第一个只出现一次的字符位置)
* [51. 数组中的逆序对](#51-数组中的逆序对)
* [52. 两个链表的第一个公共结点](#52-两个链表的第一个公共结点)
* [53 数字在排序数组中出现的次数](#53-数字在排序数组中出现的次数)
* [54. 二叉搜索树的第 k 个结点](#54-二叉搜索树的第-k-个结点)
@ -1455,7 +1456,7 @@ private void dfs(TreeNode node, int target, ArrayList<Integer> path) {
## 题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的 head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的 head。
<div align="center"> <img src="../pics//4f67aa74-5bf5-4ea4-9a6e-2e07d8f5fa86.png"/> </div><br>
@ -1519,19 +1520,21 @@ public RandomListNode Clone(RandomListNode pHead) {
```java
private TreeNode pre = null;
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree == null) return null;
inOrder(pRootOfTree);
while(pRootOfTree.left != null) pRootOfTree = pRootOfTree.left;
return pRootOfTree;
private TreeNode head = null;
public TreeNode Convert(TreeNode root) {
if (root == null) return null;
inOrder(root);
return head;
}
private void inOrder(TreeNode node) {
if(node == null) return;
if (node == null) return;
inOrder(node.left);
node.left = pre;
if(pre != null) pre.right = node;
if (pre != null) pre.right = node;
pre = node;
if (head == null) head = node;
inOrder(node.right);
}
```
@ -1578,7 +1581,7 @@ public class Solution {
## 题目描述
输入一个字符串 , 按字典序打印出该字符串中字符的所有排列。例如输入字符串 abc, 则打印出由字符 a, b, c 所能排列出来的所有字符串 abc, acb, bac, bca, cab 和 cba。
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串 abc则打印出由字符 a, b, c 所能排列出来的所有字符串 abc, acb, bac, bca, cab 和 cba。
## 解题思路
@ -1616,24 +1619,21 @@ private void backtracking(char[] chars, boolean[] hasUsed, StringBuffer s) {
多数投票问题,可以利用 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。
使用 cnt 来统计一个元素出现的次数,当遍历到的元素和统计元素不等时,令 cnt--。如果前面查找了 i 个元素,且 cnt == 0 ,说明前 i 个元素没有 majority或者有 majority但是出现的次数少于 i / 2 ,因为如果多于 i / 2 的话 cnt 就一定不会为 0 。此时剩下的 n - i 个元素中majority 的数目依然多于 (n - i) / 2因此继续查找就能找出 majority。
```java
public int MoreThanHalfNum_Solution(int[] nums) {
int cnt = 1, num = nums[0];
for (int i = 1; i < nums.length; i++) {
if (nums[i] == num) cnt++;
else cnt--;
int majority = nums[0];
for (int i = 1, cnt = 1; i < nums.length; i++) {
cnt = nums[i] == majority ? cnt + 1 : cnt - 1;
if (cnt == 0) {
num = nums[i];
majority = nums[i];
cnt = 1;
}
}
cnt = 0;
for (int i = 0; i < nums.length; i++) {
if (num == nums[i]) cnt++;
}
return cnt > nums.length / 2 ? num : 0;
int cnt = 0;
for (int val : nums) if (val == majority) cnt++;
return cnt > nums.length / 2 ? majority : 0;
}
```
@ -1644,32 +1644,32 @@ public int MoreThanHalfNum_Solution(int[] nums) {
### 快速选择
- 复杂度O(N) + O(1)
- 只有当可以修改数组元素时才可以使用
- 只有当允许修改数组元素时才可以使用
快速排序的 partition() 方法,会返回一个整数 j 使得 a[lo..j-1] 小于等于 a[j],且 a[j+1..hi] 大于等于 a[j],此时 a[j] 就是数组的第 j 大元素可以利用这个特性找出数组的第 K 个元素,这种找第 K 个元素的算法称为快速选择算法。
快速排序的 partition() 方法,会返回一个整数 j 使得 a[l..j-1] 小于等于 a[j],且 a[j+1..h] 大于等于 a[j],此时 a[j] 就是数组的第 j 大元素可以利用这个特性找出数组的第 K 个元素,这种找第 K 个元素的算法称为快速选择算法。
找到第 K 个元素之后,就可以再遍历一次数组,所有小于等于该元素的数组元素都在最小的 K 个数中
找到第 K 个元素之后,就可以再遍历一次数组,所有小于等于该元素的数组元素都是最小的 K 个数
```java
public ArrayList<Integer> GetLeastNumbers_Solution(int[] nums, int k) {
if (k > nums.length || k <= 0) return new ArrayList<>();
int kthSmallest = findKthSmallest(nums, k - 1);
ArrayList<Integer> ret = new ArrayList<>();
for (int num : nums) {
if (num <= kthSmallest && ret.size() < k) ret.add(num);
for (int val : nums) {
if (val <= kthSmallest && ret.size() < k) ret.add(val);
}
return ret;
}
public int findKthSmallest(int[] nums, int k) {
int lo = 0;
int hi = nums.length - 1;
while (lo < hi) {
int j = partition(nums, lo, hi);
int l = 0;
int h = nums.length - 1;
while (l < h) {
int j = partition(nums, l, h);
if (j < k) {
lo = j + 1;
l = j + 1;
} else if (j > k) {
hi = j - 1;
h = j - 1;
} else {
break;
}
@ -1677,29 +1677,25 @@ public int findKthSmallest(int[] nums, int k) {
return nums[k];
}
private int partition(int[] nums, int lo, int hi) {
int i = lo;
int j = hi + 1;
private int partition(int[] nums, int l, int h) {
int i = l;
int j = h + 1;
while (true) {
while (i < hi && less(nums[++i], nums[lo])) ;
while (j > lo && less(nums[lo], nums[--j])) ;
while (i < h && nums[++i] < nums[l]) ;
while (j > l && nums[l] < nums[--j]) ;
if (i >= j) {
break;
}
exch(nums, i, j);
swap(nums, i, j);
}
exch(nums, lo, j);
swap(nums, l, j);
return j;
}
private void exch(int[] nums, int i, int j) {
final int tmp = nums[i];
private void swap(int[] nums, int i, int j) {
int t = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
private boolean less(int v, int w) {
return v < w;
nums[j] = t;
}
```
@ -1708,15 +1704,15 @@ private boolean less(int v, int w) {
- 复杂度O(NlogK) + O(K)
- 特别适合处理海量数据
应该注意的是,应该使用大顶堆来维护最小堆,而不能直接创建一个小顶堆并设置一个大小,企图让小顶堆中的元素都是最小元素。
应该使用大顶堆来维护最小堆,而不能直接创建一个小顶堆并设置一个大小,企图让小顶堆中的元素都是最小元素。
维护一个大小为 K 的最小堆过程如下:先添加一个元素,添加完之后如果大顶堆的大小大于 K那么需要将大顶堆的堆顶元素去除。
维护一个大小为 K 的最小堆过程如下:在添加一个元素之后,如果大顶堆的大小大于 K那么需要将大顶堆的堆顶元素去除。
```java
public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
if (k > input.length || k <= 0) return new ArrayList<>();
public ArrayList<Integer> GetLeastNumbers_Solution(int[] nums, int k) {
if (k > nums.length || k <= 0) return new ArrayList<>();
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((o1, o2) -> o2 - o1);
for (int num : input) {
for (int num : nums) {
maxHeap.add(num);
if (maxHeap.size() > k) {
maxHeap.poll();
@ -1744,16 +1740,16 @@ public class Solution {
// 当前数据流读入的元素个数
private int N = 0;
public void Insert(Integer num) {
public void Insert(Integer val) {
// 插入要保证两个堆存于平衡状态
if (N % 2 == 0) {
// N 为偶数的情况下插入到右半边。
// 因为右半边元素都要大于左半边,但是新插入的元素不一定比左半边元素来的大,
// 因此需要先将元素插入左半边,然后利用左半边为大顶堆的特点,取出堆顶元素即为最大元素,此时插入右半边
left.add(num);
left.add(val);
right.add(left.poll());
} else {
right.add(num);
right.add(val);
left.add(right.poll());
}
N++;
@ -1801,7 +1797,7 @@ public class Solution {
## 题目描述
{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为 8从第 0 个开始,到第 3 个为止)。
{6,-3,-2,7,-15,1,2,2},连续子数组的最大和为 8从第 0 个开始,到第 3 个为止)。
## 解题思路
@ -1810,9 +1806,9 @@ public int FindGreatestSumOfSubArray(int[] nums) {
if (nums.length == 0) return 0;
int ret = Integer.MIN_VALUE;
int sum = 0;
for (int num : nums) {
if (sum <= 0) sum = num;
else sum += num;
for (int val : nums) {
if (sum <= 0) sum = val;
else sum += val;
ret = Math.max(ret, sum);
}
return ret;
@ -1821,7 +1817,9 @@ public int FindGreatestSumOfSubArray(int[] nums) {
# 43. 从 1 到 n 整数中 1 出现的次数
解题参考:[Leetcode : 233. Number of Digit One](https://leetcode.com/problems/number-of-digit-one/discuss/64381/4+-lines-O(log-n)-C++JavaPython)
## 解题思路
> [Leetcode : 233. Number of Digit One](https://leetcode.com/problems/number-of-digit-one/discuss/64381/4+-lines-O(log-n)-C++JavaPython)
```java
public int NumberOf1Between1AndN_Solution(int n) {
@ -1859,7 +1857,7 @@ public int digitAtIndex(int index) {
/**
* digit 位数的数字组成的字符串长度
* 例如 digit = 2 return 90
* 例如 digit = 2return 90
*/
private int getAmountOfDigit(int digit) {
if (digit == 1) return 10;
@ -1893,7 +1891,7 @@ private int beginNumber(int digit) {
## 解题思路
可以看成是一个排序问题,在比较两个字符串 S1 和 S2 的大小时,应该比较的是 S1+S2 和 S2+S1 的大小,如果 S1+S2 >= S2+S1那么应该把 S1 排在前面,否则应该把 S2 排在前面。
可以看成是一个排序问题,在比较两个字符串 S1 和 S2 的大小时,应该比较的是 S1+S2 和 S2+S1 的大小,如果 S1+S2 < S2+S1那么应该把 S1 排在前面否则应该把 S2 排在前面
```java
public String PrintMinNumber(int[] numbers) {
@ -1911,7 +1909,7 @@ public String PrintMinNumber(int[] numbers) {
## 题目描述
给定一个数字按照如下规则翻译成字符串0 翻译成“a”1 翻译成“b”...25 翻译成“z”。一个数字有多种翻译可能例如 12258 一共有 5 种,分别是 bccfibwfibczimcfimzi。实现一个函数用来计算一个数字有多少种不同的翻译方法。
给定一个数字按照如下规则翻译成字符串0 翻译成“a”1 翻译成“b”... 25 翻译成“z”。一个数字有多种翻译可能例如 12258 一共有 5 种,分别是 bccfibwfibczimcfimzi。实现一个函数用来计算一个数字有多少种不同的翻译方法。
## 解题思路
@ -2032,7 +2030,7 @@ public int FirstNotRepeatingChar(String str) {
}
```
## 51. 数组中的逆序对
# 51. 数组中的逆序对
## 题目描述
@ -2050,19 +2048,19 @@ public int InversePairs(int[] nums) {
return (int) (cnt % 1000000007);
}
private void mergeSortUp2Down(int[] nums, int start, int end) {
if (end - start < 1) return;
int mid = start + (end - start) / 2;
mergeSortUp2Down(nums, start, mid);
mergeSortUp2Down(nums, mid + 1, end);
merge(nums, start, mid, end);
private void mergeSortUp2Down(int[] nums, int first, int last) {
if (last - first < 1) return;
int mid = first + (last - first) / 2;
mergeSortUp2Down(nums, first, mid);
mergeSortUp2Down(nums, mid + 1, last);
merge(nums, first, mid, last);
}
private void merge(int[] nums, int start, int mid, int end) {
int i = start, j = mid + 1, k = start;
while (i <= mid || j <= end) {
private void merge(int[] nums, int first, int mid, int last) {
int i = first, j = mid + 1, k = first;
while (i <= mid || j <= last) {
if (i > mid) tmp[k] = nums[j++];
else if (j > end) tmp[k] = nums[i++];
else if (j > last) tmp[k] = nums[i++];
else if (nums[i] < nums[j]) tmp[k] = nums[i++];
else {
tmp[k] = nums[j++];
@ -2070,7 +2068,7 @@ private void merge(int[] nums, int start, int mid, int end) {
}
k++;
}
for (k = start; k <= end; k++) {
for (k = first; k <= last; k++) {
nums[k] = tmp[k];
}
}
@ -2115,7 +2113,7 @@ Input:
3
Output:
4
````
```
## 解题思路
@ -2158,16 +2156,17 @@ private int getLastK(int[] nums, int K) {
利用二叉搜索数中序遍历有序的特点。
```java
TreeNode ret;
int cnt = 0;
private TreeNode ret;
private int cnt = 0;
TreeNode KthNode(TreeNode pRoot, int k) {
public TreeNode KthNode(TreeNode pRoot, int k) {
inOrder(pRoot, k);
return ret;
}
private void inOrder(TreeNode root, int k) {
if (root == null || cnt > k) return;
if (root == null) return;
if (cnt > k) return;
inOrder(root.left, k);
cnt++;
if (cnt == k) ret = root;