lcp331

从数量最多的堆取走礼物

方法一:大根堆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public long pickGifts(int[] gifts, int k) {
int n = gifts.length;
long res = 0;
PriorityQueue<Integer> queue = new PriorityQueue<>(((o1, o2) -> o2 - o1));
for (int x : gifts)
queue.add(x);
while (k-- > 0) {
int x = queue.poll(), sqrt = (int) Math.sqrt(x);
queue.add(sqrt);
}
for (int x : queue)
res += x;
return res;
}
}

统计范围内的元音字符串数

方法一:前缀和 + 预处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public int[] vowelStrings(String[] words, int[][] queries) {
int m = queries.length, n = words.length;
boolean[] check = new boolean[n];
Set<Character> set = new HashSet<>();
set.add('a');
set.add('e');
set.add('i');
set.add('o');
set.add('u');
int index = 0;
for (String word : words) {
check[index] = (set.contains(word.charAt(0)) && set.contains(word.charAt(word.length() - 1))) ? true : false;
++index;
}
int[] preSum = new int[n + 1];
for (int i = 0; i < n; ++i)
preSum[i + 1] = preSum[i] + (check[i] ? 1 : 0);
int[] res = new int[m];
index = 0;
for (int[] query : queries) {
res[index] = preSum[query[1] + 1] - preSum[query[0]];
++index;
}
return res;
}
}

打家劫舍 IV

方法一:二分 + 记忆化搜索

枚举nums中的数字limit作为小偷的窃取能力,换句话说,小偷只能偷价值小于等于limit的房屋,如果在这个limit下,能偷大于等于k个房屋,limit可以尝试更小的数;否则limit需要尝试更大的数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Solution {
public int minCapability(int[] nums, int k) {
this.nums = nums;
n = nums.length;
int[] temp = nums.clone();
Arrays.sort(temp);
int l = 0, r = n - 1;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid, temp, k))
r = mid - 1;
else
l = mid + 1;
}
return temp[l];
}

private boolean check(int mid, int[] temp, int k) {
dp = new int[n];
Arrays.fill(dp, -1);
int limit = temp[mid];
return dfs(0, limit) >= k ? true : false;
}

private int dfs(int index, int limit) {
if (index == n)
return 0;
if (dp[index] != -1)
return dp[index];
int pass = dfs(index + 1, limit), rob = 0;
if (nums[index] <= limit)
rob = dfs(index + 2, limit) + 1;
return dp[index] = Math.max(pass, rob);
}

int[] nums, dp;
int n;
}

方法二:记忆化搜索转DP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Solution {
public int minCapability(int[] nums, int k) {
this.nums = nums;
n = nums.length;
int[] temp = nums.clone();
Arrays.sort(temp);
int l = 0, r = n - 1;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid, temp, k))
r = mid - 1;
else
l = mid + 1;
}
return temp[l];
}

private boolean check(int mid, int[] temp, int k) {
int limit = temp[mid];
// dp[i]:从房屋0~i,做多能偷的房屋数量
dp = new int[n + 2];
for (int i = 2; i < n + 2; ++i) {
dp[i] = dp[i - 1];
if (nums[i - 2] <= limit)
dp[i] = Math.max(dp[i], dp[i - 2] + 1);
}
return dp[n + 1] >= k;
}

int[] nums, dp;
int n;

}

方法三:滚动数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Solution {
public int minCapability(int[] nums, int k) {
this.nums = nums;
n = nums.length;
int[] temp = nums.clone();
Arrays.sort(temp);
int l = 0, r = n - 1;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid, temp, k))
r = mid - 1;
else
l = mid + 1;
}
return temp[l];
}

private boolean check(int mid, int[] temp, int k) {
int limit = temp[mid];
// dp[i]:从房屋0~i,做多能偷的房屋数量
dp = new int[3];
for (int i = 2; i < n + 2; ++i) {
dp[i % 3] = dp[(i - 1) % 3];
if (nums[i - 2] <= limit)
dp[i % 3] = Math.max(dp[i % 3], dp[(i - 2) % 3] + 1);
}
return dp[(n + 1) % 3] >= k;
}

int[] nums, dp;
int n;

}

lcp331
https://leopol1d.github.io/2023/08/29/lcp331/
作者
Leopold
发布于
2023年8月29日
许可协议