目录
[一,3216. 交换后字典序最小的字符串](#一,3216. 交换后字典序最小的字符串)
[二,3217. 从链表中移除在数组中存在的节点](#二,3217. 从链表中移除在数组中存在的节点)
[三,3218. 切蛋糕的最小总开销 I](#三,3218. 切蛋糕的最小总开销 I)
[四,3219. 切蛋糕的最小总开销 II](#四,3219. 切蛋糕的最小总开销 II)
一,3216. 交换后字典序最小的字符串
![](https://i-blog.csdnimg.cn/direct/696baf895d394ee99952116a0efe9405.png)
本题要求交换一次相邻字符后得到字典序最小的字符串,且要求相邻字符的的奇偶相同,我们可以直接贪心,从左往右查找第一对相邻奇偶相同且左边>右边的字符对,将两者交换就行。
代码如下:
class Solution {
public String getSmallestString(String s) {
char[] ch = s.toCharArray();
for(int i=1; i<ch.length; i++){
if(ch[i-1]>ch[i] && (ch[i]-ch[i-1])%2==0){
char tmp = ch[i-1];
ch[i-1] = ch[i];
ch[i] = tmp;
break;
}
}
return new String(ch);
}
}
二,3217. 从链表中移除在数组中存在的节点
![](https://i-blog.csdnimg.cn/direct/ae49f4a261b3412fad18fd05a9cafd6b.png)
本题是一道基础的链表题,不懂链表的可以去看看这篇双向链表详解。
代码如下:
class Solution {
public ListNode modifiedList(int[] nums, ListNode head) {
Set<Integer> set = new HashSet<>();
for(int x : nums) set.add(x);
ListNode newHead = new ListNode(0, head);
ListNode cur = newHead;
while(cur.next != null){
if(set.contains(cur.next.val)){
cur.next = cur.next.next;
}else{
cur = cur.next;
}
}
return newHead.next;
}
}
三,3218. 切蛋糕的最小总开销 I
![](https://i-blog.csdnimg.cn/direct/7c6949796dca419b89a1f76fdf7ce77f.png)
本题数据范围较小,可以使用dfs来做,可以有这样的四个参数(上端点,下端点,左端点,右端点),定义dfs(l1,r1,l2,r2):为上端点,下端点,左端点,右端点分别为l1,r1,l2,r2时切割成1x1所需要的最小开销。比如我们要在 i 处水平切一刀,那么原问题就会分成上下两个部分,即dfs(l1,i,l2,r2) + dfs(i+1,r1,l2,r2) + h[i],垂直切一刀也是同理。
如图,这里定义l < r:
![](https://i-blog.csdnimg.cn/direct/e023dbe5261a4928a9993c3947bca9b9.png)
![](https://i-blog.csdnimg.cn/direct/38a58c274e24476d9f7a651228f0141e.png)
代码如下:
class Solution {
public int minimumCost(int m, int n, int[] h, int[] v) {
memo = new int[m][m][n][n];
for(int i=0; i<m; i++)
for(int j=0; j<m; j++)
for(int k=0; k<n; k++)
Arrays.fill(memo[i][j][k], -1);
return dfs(0, m-1, 0, n-1, h, v);
}
int[][][][] memo;
int dfs(int l1, int r1, int l2, int r2, int[] h, int[] v){
if(l1 == r1 && l2 == r2) return 0;
if(memo[l1][r1][l2][r2] != -1) return memo[l1][r1][l2][r2];
int res = Integer.MAX_VALUE;
for(int i=l1; i<r1; i++){
res = Math.min(res, dfs(l1, i, l2, r2, h, v) + dfs(i+1, r1, l2, r2, h, v) + h[i]);
}
for(int i=l2; i<r2; i++){
res = Math.min(res, dfs(l1, r1, l2, i, h, v) + dfs(l1, r1, i+1, r2, h, v) + v[i]);
}
return memo[l1][r1][l2][r2] = res;
}
}
四,3219. 切蛋糕的最小总开销 II
![](https://i-blog.csdnimg.cn/direct/efd0c327a4ee4362a9955287ac1ec9fb.png)
本题就不能使用上述做法,会超时,可以使用贪心来做,如图:
代码如下:
class Solution {
public long minimumCost(int m, int n, int[] h, int[] v) {
Arrays.sort(h);
Arrays.sort(v);
int i = m-2, j = n-2;
int cntH = 1, cntV = 1;
long ans = 0;
while(i >= 0 && j >= 0){
if(v[j] > h[i]){
ans += cntV*v[j];
cntH++;
j--;
}else{
ans += cntH*h[i];
cntV++;
i--;
}
}
while(i >= 0){
ans += cntH*h[i];
i--;
}
while(j >= 0){
ans += cntV*v[j];
j--;
}
return ans;
}
}