Skip to content

Commit 2ff20bb

Browse files
committed
2020-5-6
1 parent 616805d commit 2ff20bb

File tree

4 files changed

+81
-52
lines changed

4 files changed

+81
-52
lines changed

question0300_longest_increasing_subsequence/Solution1.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@
44
* 动态规划。
55
*
66
* 状态定义:
7-
* dp[i],以索引i处数字结尾的最长上升子序列的长度
7+
* dp[i]表示以索引i处数字结尾的最长上升子序列的长度
88
*
9-
* 状态转移:
10-
* dp[0] = 1
11-
* 当i > 0时,dp[i] = Math.max(dp[j] + 1, dp[i]),其中j∈[0, i)且nums[i] > nums[j]
9+
* 初始化条件:
10+
* dp[0] = 1。
11+
*
12+
* 状态转移方程:
13+
* dp[i] = Math.max(dp[j] + 1, dp[i]),其中j∈[0, i)且nums[i] > nums[j]。
1214
*
1315
* 时间复杂度是O(n ^ 2),其中n为nums数组的长度。空间复杂度是O(n)。
1416
*
15-
* 执行用时:22ms,击败65.26%。消耗内存:36.6MB,击败31.51%。
17+
* 执行用时:36ms,击败5.39%。消耗内存:37.6MB,击败7.14%。
1618
*/
1719
public class Solution1 {
1820
public int lengthOfLIS(int[] nums) {

question0300_longest_increasing_subsequence/Solution2.java

Lines changed: 25 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,10 @@
33
/**
44
* 二分查找法。
55
*
6-
* 首先,我们需要一个n行的二维数组,其中第0行记录长度为1的一个"上升子序列",第1行记录长度为2的一个"上升子序列",...,
7-
* 第n - 1行记录长度为n的一个"上升子序列"。所有的这些子序列满足一个条件:它们的"结尾"是所有相同长度的"上升子序列"里面最小的。
8-
*
9-
* 以数组[10, 9, 2, 5, 3, 7, 101, 18]为例进行说明:
10-
*
11-
* 首先我们需要一个8行的数组,初始均为空:
12-
* [[], [], [], [], [], [], [], []]
13-
*
14-
* (1)遍历第0个元素——10,此时我们填充第0行:
15-
* [[10], [], [], [], [], [], [], []]
16-
* (2)遍历第1个元素——9,此时我们的数组如下:
17-
* [[9], [], [], [], [], [], [], []]
18-
* (3)遍历第2个元素——2,此时我们的数组如下:
19-
* [[2], [], [], [], [], [], [], []]
20-
* (4)遍历第3个元素——5,5比2大,此时我们填充第1行:
21-
* [[2], [2, 5], [], [], [], [], [], []]
22-
* (5)遍历第4个元素——3,3比2大比5小,此时我们的数组如下:
23-
* [[2], [2, 3], [], [], [], [], [], []]
24-
* (6)遍历第5个元素——7,7比3大,此时我们填充第2行:
25-
* [[2], [2, 3], [2, 3, 7], [], [], [], [], []]
26-
* (7)遍历第6个元素——101,101比7大,此时我们填充第3行:
27-
* [[2], [2, 3], [2, 3, 7], [2, 3, 7, 101], [], [], [], []]
28-
* (8)遍历第7个元素——18,18比7大,比101小,此时我们的数组如下:
29-
* [[2], [2, 3], [2, 3, 7], [2, 3, 7, 18], [], [], [], []]
30-
*
31-
* 遍历完成后,我们发现总共填充了3行,因此最长子序列长度就是4。
32-
*
33-
* 在整个过程中,我们只用到了第i行的最后一个元素,因此我们只需要用一个一维数组tail来保存某行的最后一个元素即可。
6+
* 扑克牌分堆放置,放置规则如下:
7+
* (1)只能把点数小的牌压到点数比它大的牌上。
8+
* (2)如果当前牌点数较大没有可以放置的堆,则新建一个堆,把这张牌放进去。
9+
* (3)如果当前牌有多个堆可供选择, 则选择最左边的堆放置。
3410
*
3511
* 时间复杂度是O(nlogn),其中n为nums数组的长度。空间复杂度是O(n)。
3612
*
@@ -42,28 +18,30 @@ public int lengthOfLIS(int[] nums) {
4218
if (nums == null || (n = nums.length) == 0) {
4319
return 0;
4420
}
45-
int[] tail = new int[n];
46-
tail[0] = nums[0];
47-
int end = 0; //end表示有序数组tail的最后一个已经赋值元素的索引
21+
int[] tops = new int[n]; // 每堆扑克牌堆顶的牌
22+
tops[0] = nums[0]; // 第一张牌显然只能新建一堆
23+
int piles = 1; // 现在一共有piles堆扑克牌
4824
for (int i = 1; i < n; i++) {
49-
if (nums[i] > tail[end]) { //得到一个长度+1的新的上升子序列
50-
tail[++end] = nums[i];
51-
} else {
52-
//ceil()函数二分查找,在tail数组[0, end]范围内找到大于nums[i]的元素,更新其值
53-
int left = 0, right = end + 1;
54-
while (left < right) {
55-
int mid = left + ((right - left) >> 1);
56-
if (tail[mid] <= nums[i]) {
57-
left = mid + 1;
58-
} else {
59-
right = mid;
60-
}
61-
}
62-
if (left - 1 < 0 || tail[left - 1] != nums[i]) { //如果nums[i]在tail数组的[0, end]范围内已经存在,什么都不做
63-
tail[left] = nums[i]; //更新tail[left]值为nums[i]
25+
// 在[0, piles - 1]范围内寻找第一处比nums[i]大的位置,即ceil函数
26+
int left = 0, right = piles - 1;
27+
while (left <= right) {
28+
int mid = left + ((right - left) >> 1);
29+
if (tops[mid] == nums[i]) {
30+
left = mid + 1;
31+
} else if (tops[mid] < nums[i]) {
32+
left = mid + 1;
33+
} else if (tops[mid] > nums[i]) {
34+
right = mid - 1;
6435
}
6536
}
37+
if (left - 1 >= 0 && tops[left - 1] == nums[i]) {
38+
continue;
39+
}
40+
if (left == piles) {
41+
piles++;
42+
}
43+
tops[left] = nums[i];
6644
}
67-
return end + 1;
45+
return piles;
6846
}
6947
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package question0983_minimum_cost_for_tickets;
2+
3+
/**
4+
* 动态规划。
5+
*
6+
* 时间复杂度是O(n ^ 2),其中n为days数组的长度。空间复杂度是O(n)。
7+
*
8+
* 执行用时:2ms,击败48.29%。消耗内存:37.6MB,击败100.00%。
9+
*/
10+
public class Solution {
11+
public int mincostTickets(int[] days, int[] costs) {
12+
int[] dp = new int[days.length];
13+
dp[days.length - 1] = Math.min(costs[0], Math.min(costs[1], costs[2]));
14+
for (int i = days.length - 2; i >= 0; i--) {
15+
dp[i] = dp[i + 1] + costs[0];
16+
int tmp = i;
17+
while (tmp < days.length && days[tmp] - days[i] < 7) {
18+
tmp++;
19+
}
20+
if (tmp != i && tmp < days.length) {
21+
dp[i] = Math.min(dp[i], dp[tmp] + costs[1]);
22+
} else {
23+
dp[i] = Math.min(dp[i], costs[1]);
24+
}
25+
tmp = i;
26+
while (tmp < days.length && days[tmp] - days[i] < 30) {
27+
tmp++;
28+
}
29+
if (tmp != i && tmp < days.length) {
30+
dp[i] = Math.min(dp[i], dp[tmp] + costs[2]);
31+
} else {
32+
dp[i] = Math.min(dp[i], costs[2]);
33+
}
34+
}
35+
return dp[0];
36+
}
37+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package question1012_numbers_with_repeated_digits;
2+
3+
public class Solution {
4+
public int numDupDigitsAtMostN(int N) {
5+
if (N <= 10) {
6+
return 0;
7+
} else if (N < 100) {
8+
return 1 + (N - 11) / 10;
9+
}
10+
return -1;
11+
}
12+
}

0 commit comments

Comments
 (0)