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-最长不含重复字符的子字符串) * [48. 最长不含重复字符的子字符串](#48-最长不含重复字符的子字符串)
* [49. 丑数](#49-丑数) * [49. 丑数](#49-丑数)
* [50. 第一个只出现一次的字符位置](#50-第一个只出现一次的字符位置) * [50. 第一个只出现一次的字符位置](#50-第一个只出现一次的字符位置)
* [51. 数组中的逆序对](#51-数组中的逆序对)
* [52. 两个链表的第一个公共结点](#52-两个链表的第一个公共结点) * [52. 两个链表的第一个公共结点](#52-两个链表的第一个公共结点)
* [53 数字在排序数组中出现的次数](#53-数字在排序数组中出现的次数) * [53 数字在排序数组中出现的次数](#53-数字在排序数组中出现的次数)
* [54. 二叉搜索树的第 k 个结点](#54-二叉搜索树的第-k-个结点) * [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> <div align="center"> <img src="../pics//4f67aa74-5bf5-4ea4-9a6e-2e07d8f5fa86.png"/> </div><br>
@ -1519,11 +1520,12 @@ public RandomListNode Clone(RandomListNode pHead) {
```java ```java
private TreeNode pre = null; private TreeNode pre = null;
public TreeNode Convert(TreeNode pRootOfTree) { private TreeNode head = null;
if(pRootOfTree == null) return null;
inOrder(pRootOfTree); public TreeNode Convert(TreeNode root) {
while(pRootOfTree.left != null) pRootOfTree = pRootOfTree.left; if (root == null) return null;
return pRootOfTree; inOrder(root);
return head;
} }
private void inOrder(TreeNode node) { private void inOrder(TreeNode node) {
@ -1532,6 +1534,7 @@ private void inOrder(TreeNode node) {
node.left = pre; node.left = pre;
if (pre != null) pre.right = node; if (pre != null) pre.right = node;
pre = node; pre = node;
if (head == null) head = node;
inOrder(node.right); 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)。 多数投票问题,可以利用 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 ```java
public int MoreThanHalfNum_Solution(int[] nums) { public int MoreThanHalfNum_Solution(int[] nums) {
int cnt = 1, num = nums[0]; int majority = nums[0];
for (int i = 1; i < nums.length; i++) { for (int i = 1, cnt = 1; i < nums.length; i++) {
if (nums[i] == num) cnt++; cnt = nums[i] == majority ? cnt + 1 : cnt - 1;
else cnt--;
if (cnt == 0) { if (cnt == 0) {
num = nums[i]; majority = nums[i];
cnt = 1; cnt = 1;
} }
} }
cnt = 0; int cnt = 0;
for (int i = 0; i < nums.length; i++) { for (int val : nums) if (val == majority) cnt++;
if (num == nums[i]) cnt++; return cnt > nums.length / 2 ? majority : 0;
}
return cnt > nums.length / 2 ? num : 0;
} }
``` ```
@ -1644,32 +1644,32 @@ public int MoreThanHalfNum_Solution(int[] nums) {
### 快速选择 ### 快速选择
- 复杂度O(N) + O(1) - 复杂度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 ```java
public ArrayList<Integer> GetLeastNumbers_Solution(int[] nums, int k) { public ArrayList<Integer> GetLeastNumbers_Solution(int[] nums, int k) {
if (k > nums.length || k <= 0) return new ArrayList<>(); if (k > nums.length || k <= 0) return new ArrayList<>();
int kthSmallest = findKthSmallest(nums, k - 1); int kthSmallest = findKthSmallest(nums, k - 1);
ArrayList<Integer> ret = new ArrayList<>(); ArrayList<Integer> ret = new ArrayList<>();
for (int num : nums) { for (int val : nums) {
if (num <= kthSmallest && ret.size() < k) ret.add(num); if (val <= kthSmallest && ret.size() < k) ret.add(val);
} }
return ret; return ret;
} }
public int findKthSmallest(int[] nums, int k) { public int findKthSmallest(int[] nums, int k) {
int lo = 0; int l = 0;
int hi = nums.length - 1; int h = nums.length - 1;
while (lo < hi) { while (l < h) {
int j = partition(nums, lo, hi); int j = partition(nums, l, h);
if (j < k) { if (j < k) {
lo = j + 1; l = j + 1;
} else if (j > k) { } else if (j > k) {
hi = j - 1; h = j - 1;
} else { } else {
break; break;
} }
@ -1677,29 +1677,25 @@ public int findKthSmallest(int[] nums, int k) {
return nums[k]; return nums[k];
} }
private int partition(int[] nums, int lo, int hi) { private int partition(int[] nums, int l, int h) {
int i = lo; int i = l;
int j = hi + 1; int j = h + 1;
while (true) { while (true) {
while (i < hi && less(nums[++i], nums[lo])) ; while (i < h && nums[++i] < nums[l]) ;
while (j > lo && less(nums[lo], nums[--j])) ; while (j > l && nums[l] < nums[--j]) ;
if (i >= j) { if (i >= j) {
break; break;
} }
exch(nums, i, j); swap(nums, i, j);
} }
exch(nums, lo, j); swap(nums, l, j);
return j; return j;
} }
private void exch(int[] nums, int i, int j) { private void swap(int[] nums, int i, int j) {
final int tmp = nums[i]; int t = nums[i];
nums[i] = nums[j]; nums[i] = nums[j];
nums[j] = tmp; nums[j] = t;
}
private boolean less(int v, int w) {
return v < w;
} }
``` ```
@ -1708,15 +1704,15 @@ private boolean less(int v, int w) {
- 复杂度O(NlogK) + O(K) - 复杂度O(NlogK) + O(K)
- 特别适合处理海量数据 - 特别适合处理海量数据
应该注意的是,应该使用大顶堆来维护最小堆,而不能直接创建一个小顶堆并设置一个大小,企图让小顶堆中的元素都是最小元素。 应该使用大顶堆来维护最小堆,而不能直接创建一个小顶堆并设置一个大小,企图让小顶堆中的元素都是最小元素。
维护一个大小为 K 的最小堆过程如下:先添加一个元素,添加完之后如果大顶堆的大小大于 K那么需要将大顶堆的堆顶元素去除。 维护一个大小为 K 的最小堆过程如下:在添加一个元素之后,如果大顶堆的大小大于 K那么需要将大顶堆的堆顶元素去除。
```java ```java
public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) { public ArrayList<Integer> GetLeastNumbers_Solution(int[] nums, int k) {
if (k > input.length || k <= 0) return new ArrayList<>(); if (k > nums.length || k <= 0) return new ArrayList<>();
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((o1, o2) -> o2 - o1); PriorityQueue<Integer> maxHeap = new PriorityQueue<>((o1, o2) -> o2 - o1);
for (int num : input) { for (int num : nums) {
maxHeap.add(num); maxHeap.add(num);
if (maxHeap.size() > k) { if (maxHeap.size() > k) {
maxHeap.poll(); maxHeap.poll();
@ -1744,16 +1740,16 @@ public class Solution {
// 当前数据流读入的元素个数 // 当前数据流读入的元素个数
private int N = 0; private int N = 0;
public void Insert(Integer num) { public void Insert(Integer val) {
// 插入要保证两个堆存于平衡状态 // 插入要保证两个堆存于平衡状态
if (N % 2 == 0) { if (N % 2 == 0) {
// N 为偶数的情况下插入到右半边。 // N 为偶数的情况下插入到右半边。
// 因为右半边元素都要大于左半边,但是新插入的元素不一定比左半边元素来的大, // 因为右半边元素都要大于左半边,但是新插入的元素不一定比左半边元素来的大,
// 因此需要先将元素插入左半边,然后利用左半边为大顶堆的特点,取出堆顶元素即为最大元素,此时插入右半边 // 因此需要先将元素插入左半边,然后利用左半边为大顶堆的特点,取出堆顶元素即为最大元素,此时插入右半边
left.add(num); left.add(val);
right.add(left.poll()); right.add(left.poll());
} else { } else {
right.add(num); right.add(val);
left.add(right.poll()); left.add(right.poll());
} }
N++; 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; if (nums.length == 0) return 0;
int ret = Integer.MIN_VALUE; int ret = Integer.MIN_VALUE;
int sum = 0; int sum = 0;
for (int num : nums) { for (int val : nums) {
if (sum <= 0) sum = num; if (sum <= 0) sum = val;
else sum += num; else sum += val;
ret = Math.max(ret, sum); ret = Math.max(ret, sum);
} }
return ret; return ret;
@ -1821,7 +1817,9 @@ public int FindGreatestSumOfSubArray(int[] nums) {
# 43. 从 1 到 n 整数中 1 出现的次数 # 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 ```java
public int NumberOf1Between1AndN_Solution(int n) { public int NumberOf1Between1AndN_Solution(int n) {
@ -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 ```java
public String PrintMinNumber(int[] numbers) { public String PrintMinNumber(int[] numbers) {
@ -2032,7 +2030,7 @@ public int FirstNotRepeatingChar(String str) {
} }
``` ```
## 51. 数组中的逆序对 # 51. 数组中的逆序对
## 题目描述 ## 题目描述
@ -2050,19 +2048,19 @@ public int InversePairs(int[] nums) {
return (int) (cnt % 1000000007); return (int) (cnt % 1000000007);
} }
private void mergeSortUp2Down(int[] nums, int start, int end) { private void mergeSortUp2Down(int[] nums, int first, int last) {
if (end - start < 1) return; if (last - first < 1) return;
int mid = start + (end - start) / 2; int mid = first + (last - first) / 2;
mergeSortUp2Down(nums, start, mid); mergeSortUp2Down(nums, first, mid);
mergeSortUp2Down(nums, mid + 1, end); mergeSortUp2Down(nums, mid + 1, last);
merge(nums, start, mid, end); merge(nums, first, mid, last);
} }
private void merge(int[] nums, int start, int mid, int end) { private void merge(int[] nums, int first, int mid, int last) {
int i = start, j = mid + 1, k = start; int i = first, j = mid + 1, k = first;
while (i <= mid || j <= end) { while (i <= mid || j <= last) {
if (i > mid) tmp[k] = nums[j++]; 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 if (nums[i] < nums[j]) tmp[k] = nums[i++];
else { else {
tmp[k] = nums[j++]; tmp[k] = nums[j++];
@ -2070,7 +2068,7 @@ private void merge(int[] nums, int start, int mid, int end) {
} }
k++; k++;
} }
for (k = start; k <= end; k++) { for (k = first; k <= last; k++) {
nums[k] = tmp[k]; nums[k] = tmp[k];
} }
} }
@ -2115,7 +2113,7 @@ Input:
3 3
Output: Output:
4 4
```` ```
## 解题思路 ## 解题思路
@ -2158,16 +2156,17 @@ private int getLastK(int[] nums, int K) {
利用二叉搜索数中序遍历有序的特点。 利用二叉搜索数中序遍历有序的特点。
```java ```java
TreeNode ret; private TreeNode ret;
int cnt = 0; private int cnt = 0;
TreeNode KthNode(TreeNode pRoot, int k) { public TreeNode KthNode(TreeNode pRoot, int k) {
inOrder(pRoot, k); inOrder(pRoot, k);
return ret; return ret;
} }
private void inOrder(TreeNode root, int k) { 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); inOrder(root.left, k);
cnt++; cnt++;
if (cnt == k) ret = root; if (cnt == k) ret = root;