携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情 >>
每日三刷,剑指千题
计划简介:
- 每日三题,以中等题为主,简单题为辅进行搭配。保证质量题1道,数量题3道。
- 每日早通勤在LeetCode手机端选题,思考思路,没答案的直接看题解。
- 每日中午进行编码,时间控制在一小时之内。
- 下班前半小时进行整理总结,并发布到掘金每日更文活动。
说明:
- 基于以前的刷题基础,本次计划以中等题为主,大部分中等题都可以拆分为多个简单题,所以数量保证3,质量保证一道中等题即可。
- 刷题顺序按照先刷链表、二叉树、栈、堆、队列等基本数据结构,再刷递归、二分法、排序、双指针等基础算法,最后是动态规划、贪心、回溯、搜索等复杂算法。
- 刷题过程中整理相似题型,刷题模板。
- 目前进度 165/1000 。
今日题型
双指针
[541]反转字符串 II
给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
- 如果剩余字符少于
k个,则将剩余字符全部反转。 - 如果剩余字符小于
2k但大于或等于k个,则反转前k个字符,其余字符保持原样。
示例 1:
输入:s = "abcdefg", k = 2
输出:"bacdfeg"
解析
局部双指针,再将结果合并。
Code
class Solution {
public String reverseStr(String s, int k) {
char[] chars = s.toCharArray();
int count = s.length() / (2 * k) + 1;
int times = 0;
while (times < count) {
int head = times * 2 * k;
int tail = Math.min(times * 2 * k + k - 1, s.length() - 1);
while (head < tail) {
char c = chars[head];
chars[head] = chars[tail];
chars[tail] = c;
head++;
tail--;
}
times++;
}
return String.copyValueOf(chars);
}
}
[剑指 Offer 57]和为s的两个数字
输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[2,7] 或者 [7,2]
解析
典型双指针题
Code
class Solution {
public int[] twoSum(int[] nums, int target) {
int head = 0, tail = nums.length - 1;
while (head < tail) {
if (nums[head] + nums[tail] == target) {
return new int[]{nums[head], nums[tail]};
} else if (nums[head] + nums[tail] > target) {
tail--;
} else {
head++;
}
}
return new int[2];
}
}
[80]删除有序数组中的重复项 II
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
示例 1:
输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3]
解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。 不需要考虑数组中超出新长度后面的元素。
解析
参考【宫水三叶的通用解法】
但我觉得用 for 循环写 不太好理解,对我个人来说吧,我觉得用 while 更体现双指针。
Code
class Solution {
public int removeDuplicates(int[] nums) {
int head = 0, tail = 0;
while (head < nums.length) {
if (2 > tail || nums[tail - 2] != nums[head]) {
nums[tail++] = nums[head];
}
head++;
}
return tail;
}
}
\