[Leetcode Weekly Contest]296
链接:LeetCode
[Leetcode]2293. 极大极小游戏
给你一个下标从 0 开始的整数数组 nums ,其长度是 2 的幂。
对 nums 执行下述算法:
- 设 n 等于 nums 的长度,如果 n == 1 ,终止 算法过程。否则,创建 一个新的整数数组 newNums ,新数组长度为 n / 2 ,下标从 0 开始。
- 对于满足 0 <= i < n / 2 的每个 偶数 下标 i ,将 newNums[i] 赋值 为 min(nums[2 * i], nums[2 * i + 1]) 。
- 对于满足 0 <= i < n / 2 的每个 奇数 下标 i ,将 newNums[i] 赋值 为 max(nums[2 * i], nums[2 * i + 1]) 。
- 用 newNums 替换 nums 。
- 从步骤 1 开始 重复 整个过程。
执行算法后,返回 nums 中剩下的那个数字。
模拟遍历即可。
class Solution {
public int minMaxGame(int[] nums) {
while(nums.length!=1) {
int[] nextNums = new int[nums.length/2];
boolean minFlag = true;
for(int i=0;i<nextNums.length;++i) {
if(minFlag) nextNums[i] = Math.min(nums[2*i], nums[2*i+1]);
else nextNums[i] = Math.max(nums[2*i], nums[2*i+1]);
minFlag = !minFlag;
}
nums = nextNums;
}
return nums[0];
}
}
[Leetcode]2294. 划分数组使最大差为 K
给你一个整数数组 nums 和一个整数 k 。你可以将 nums 划分成一个或多个 子序列 ,使 nums 中的每个元素都 恰好 出现在一个子序列中。
在满足每个子序列中最大值和最小值之间的差值最多为 k 的前提下,返回需要划分的 最少 子序列数目。
子序列 本质是一个序列,可以通过删除另一个序列中的某些元素(或者不删除)但不改变剩下元素的顺序得到。
由于选的是子序列,且只需要考虑每个子序列中的最小值和最大值,与子序列中元素的顺序无关,因此我们可以对数组排序。
排序后对数组分组,每组内的元素最大减最小不能超过 k。这可以通过遍历一遍数组来判断,并得到组数。
class Solution {
public int partitionArray(int[] nums, int k) {
Arrays.sort(nums);
int res = 1;
int pre = nums[0];
for(int i=1;i<nums.length;++i) {
if(nums[i] - pre > k) {
res ++ ;
pre = nums[i];
}
}
return res;
}
}
[Leetcode]2295. 替换数组中的元素
给你一个下标从 0 开始的数组 nums ,它包含 n 个 互不相同 的正整数。请你对这个数组执行 m 个操作,在第 i 个操作中,你需要将数字 operations[i][0] 替换成 operations[i][1] 。
题目保证在第 i 个操作中:
- operations[i][0] 在 nums 中存在。
- operations[i][1] 在 nums 中不存在。
请你返回执行完所有操作后的数组。
两种做法:正序(利用特殊条件) or 逆序(更加通用)。注意到 \(\textit{nums}\) 的元素互不相同,且每次操作总是将一个在 \(\textit{nums}\) 中的元素变成一个不在 \(\textit{nums}\) 中的元素,因此每次操作之后 \(\textit{nums}\) 的元素仍然互不相同。
用哈希表存储每个元素的位置,然后遍历 \(\textit{operations}\) 数组模拟即可。
如果 \(\textit{nums}\) 中有重复元素呢?有没有更加通用的做法?
设 \(x=\textit{operations}[i][0]\),\(y=\textit{operations}[i][1]\),我们可以倒着遍历 \(\textit{operations}\),同时用一个哈希表 \(\textit{mp}\) 将 x 映射到 \(\textit{mp}[y]\) 上,如果 \(\textit{mp}[y]\) 不存在则直接映射到 y 上。
例如,先把 1 变成 2,再把 2 变成 3,如果倒着来的话,就是 2 变成 3,那么对于 1 来说,可以直接知道最终是会变成 3 的。
class Solution {
public int[] arrayChange(int[] nums, int[][] operations) {
HashMap<Integer, Integer> hash = new HashMap<>();
int n = operations.length;
for(int i=n-1;i>=0;--i) {
int pre = operations[i][0], nxt = operations[i][1];
hash.put(pre, hash.getOrDefault(nxt, nxt));
}
for(int i=0;i<nums.length;++i) {
nums[i] = hash.getOrDefault(nums[i], nums[i]);
}
return nums;
}
public int[] arrayChange2(int[] nums, int[][] operations) {
HashMap<Integer, Integer> hash = new HashMap<>();
for(int i=0;i<nums.length;++i) hash.put(nums[i], i);
for(var operation: operations) {
int pre = operation[0], nxt = operation[1];
int idx = hash.get(pre);
nums[idx] = nxt;
hash.put(nxt, idx);
hash.remove(pre);
}
return nums;
}
}
[Leetcode]2296. 设计一个文本编辑器
请你设计一个带光标的文本编辑器,它可以实现以下功能:
- 添加:在光标所在处添加文本。
- 删除:在光标所在处删除文本(模拟键盘的删除键)。
- 移动:将光标往左或者往右移动。
- 当删除文本时,只有光标左边的字符会被删除。光标会留在文本内,也就是说任意时候 0 <= cursor.position <= currentText.length 都成立。
请你实现 TextEditor 类:
- TextEditor() 用空文本初始化对象。
- void addText(string text) 将 text 添加到光标所在位置。添加完后光标在 text 的右边。
- int deleteText(int k) 删除光标左边 k 个字符。返回实际删除的字符数目。
- string cursorLeft(int k) 将光标向左移动 k 次。返回移动后光标左边 min(10, len) 个字符,其中 len 是光标左边的字符数目。
- string cursorRight(int k) 将光标向右移动 k 次。返回移动后光标左边 min(10, len) 个字符,其中 len 是光标左边的字符数目。
对顶栈。用两个栈头对头,光标的左右移动就相当于两个栈来回倒;对于插入和删除操作,就相当于在左边那个栈上入栈出栈。
class TextEditor {
ArrayDeque<Character> queueleft = new ArrayDeque<>();
ArrayDeque<Character> queueright = new ArrayDeque<>();
int pos = 0;
public TextEditor() {
}
public void addText(String text) {
for(var ch:text.toCharArray()) {
queueleft.push(ch);
}
}
public int deleteText(int k) {
int res = 0;
for(int i=0;i<k;++i) {
if(!queueleft.isEmpty()) queueleft.pop();
else break;
res ++;
}
return res;
}
public String cursorLeft(int k) {
for(int i=0;i<k;++i) {
if(queueleft.isEmpty()) break;
char ch = queueleft.pop();
queueright.push(ch);
}
String res = "";
for(int i=0;i<10;++i) {
if(queueleft.isEmpty()) break;
res = queueleft.pop() + res;
}
addText(res);
return res;
}
public String cursorRight(int k) {
for(int i=0;i<k;++i) {
if(queueright.isEmpty()) break;
char ch = queueright.pop();
queueleft.push(ch);
}
String res = "";
for(int i=0;i<10;++i) {
if(queueleft.isEmpty()) break;
res = queueleft.pop() + res;
}
addText(res);
return res;
}
}
/**
* Your TextEditor object will be instantiated and called as such:
* TextEditor obj = new TextEditor();
* obj.addText(text);
* int param_2 = obj.deleteText(k);
* String param_3 = obj.cursorLeft(k);
* String param_4 = obj.cursorRight(k);
*/
参考:LeetCode