文章目录
- 0. Leetcode [917. 仅仅反转字母](https://leetcode-cn.com/problems/reverse-only-letters/)
- 1. Leetcode [167. 两数之和 II - 输入有序数组](https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/)
- 2. Leetcode [165. 比较版本号](https://leetcode-cn.com/problems/compare-version-numbers/)
- 3. Leetcode [443. 压缩字符串](https://leetcode-cn.com/problems/string-compression/solution/ya-suo-zi-fu-chuan-by-leetcode-solution-kbuc/)
- 总结
0. Leetcode 917. 仅仅反转字母
给你一个字符串 s ,根据下述规则反转字符串:
所有非英文字母保留在原有位置。
所有英文字母(小写或大写)位置反转。
返回反转后的 s 。
分析与解答
借用双指针的思想,要调换单词中所有字母的顺序,只需要首尾配对找到相应字母位置即可。因此令 i 从头开始,j 从尾开始寻找字母,找到后进行调换,直至 i >= j,表明已交换单词中的所有字母。
class Solution {
public:
string reverseOnlyLetters(string s) {
for (int i = 0, j = s.size() - 1; i < j;) {
while (!(tolower(s[i]) >= 'a' && tolower(s[i]) <= 'z') && i < j) {
i++;
}
while (!(tolower(s[j]) >= 'a' && tolower(s[j]) <= 'z') && i < j) {
j--;
}
if (i >= j) {
break;
} else {
char tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
// 交换完后将指针移到下一个待判断字符
i++;
j--;
}
return s;
}
};
算法时间复杂度为 O ( N ) O(N) O(N)
1. Leetcode 167. 两数之和 II - 输入有序数组
给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。
以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。
你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
你所设计的解决方案必须只使用常量级的额外空间。
分析与解答
解法1:二分查找
对于该问题,从头至尾遍历数组,对每个数 num,二分查找 target - num 在数组中是否存在。
class Solution {
public:
int findPos(vector<int>& numbers, int low, int high, int target) {
int l(low), r(high);
while (l <= r) {
int mid = l + ((r - l) >> 1);
if (numbers[mid] < target) {
l = mid + 1;
} else if (numbers[mid] > target) {
r = mid - 1;
} else {
return mid;
}
}
return -1;
}
vector<int> twoSum(vector<int>& numbers, int target) {
vector<int> result;
bool find(false);
for (int i = 0; i < numbers.size(); ++i) {
int idx = findPos(numbers, i+1, numbers.size() - 1, target - numbers[i]);
if (idx > 0) {
result.push_back(i+1);
result.push_back(idx+1);
break;
}
}
return result;
}
};
算法时间复杂度为
O
(
N
l
o
g
N
)
O(NlogN)
O(NlogN)
解法2:双指针
令两个指针分别指向首数字与尾数字,若两数和大于 target,则尾指针前移;若两数和大于 target,则首指针后移。
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
vector<int> result;
int i(0), j(numbers.size() - 1);
while (i < j) {
if (numbers[i] + numbers[j] < target) {
i++;
} else if (numbers[i] + numbers[j] > target) {
j--;
} else {
result.push_back(i + 1);
result.push_back(j + 1);
break;
}
}
return result;
}
};
算法时间复杂度为 O ( N ) O(N) O(N)
2. Leetcode 165. 比较版本号
给你两个版本号 version1 和 version2 ,请你比较它们。
版本号由一个或多个修订号组成,各修订号由一个 ‘.’ 连接。每个修订号由 多位数字 组成,可能包含 前导零 。每个版本号至少包含一个字符。修订号从左到右编号,下标从 0 开始,最左边的修订号下标为 0 ,下一个修订号下标为 1 ,以此类推。例如,2.5.33 和 0.1 都是有效的版本号。
比较版本号时,请按从左到右的顺序依次比较它们的修订号。比较修订号时,只需比较 忽略任何前导零后的整数值 。也就是说,修订号 1 和修订号 001 相等 。如果版本号没有指定某个下标处的修订号,则该修订号视为 0 。例如,版本 1.0 小于版本 1.1 ,因为它们下标为 0 的修订号相同,而下标为 1 的修订号分别为 0 和 1 ,0 < 1 。
返回规则如下:
如果 version1 > version2 返回 1,
如果 version1 < version2 返回 -1,
除此之外返回 0。
分析与解答
令两个指针指向字符串头,后移指针 r,直至找到字符 .,此时从指针间取出字串,进行比较。重复这一过程直至遍历完成。
class Solution {
public:
int compareVersion(string version1, string version2) {
int l0(0), r0(0);
int l1(0), r1(0);
int result(0);
version1 += ".";
version2 += ".";
while (r0 < version1.size() || r1 < version2.size()) {
string str1 = "0";
string str2 = "0";
if (r0 < version1.size()) {
while (version1[r0] != '.') {
r0++;
}
while (version1[l0] == '0') {
l0++;
}
if (r0 - l0 > 0) {
str1 = version1.substr(l0, r0 - l0);
}
}
if (r1 < version2.size()) {
while (version2[r1] != '.') {
r1++;
}
while (version2[l1] == '0') {
l1++;
}
if (r1 - l1 > 0) {
str2 = version2.substr(l1, r1 - l1);
}
}
if (stoi(str1) < stoi(str2)) {
result = -1;
break;
} else if (stoi(str1) > stoi(str2)) {
result = 1;
break;
}
r0++;
l0 = r0;
r1++;
l1 = r1;
}
return result;
}
};
算法时间复杂度为 O ( N ) O(N) O(N)
3. Leetcode 443. 压缩字符串
给你一个字符数组 chars ,请使用下述算法压缩:
从一个空字符串 s 开始。对于 chars 中的每组 连续重复字符 :
如果这一组长度为 1 ,则将字符追加到 s 中。
否则,需要向 s 追加字符,后跟这一组的长度。
压缩后得到的字符串 s 不应该直接返回 ,需要转储到字符数组 chars 中。需要注意的是,如果组长度为 10 或 10 以上,则在 chars 数组中会被拆分为多个字符。
请在 修改完输入数组后 ,返回该数组的新长度。
你必须设计并实现一个只使用常量额外空间的算法来解决此问题。
分析与解答
令指针 i 作为写指针,记录写字符的位置;指针 j 作为读指针,记录读取字符的位置,后移指针 j 直至新字符与前一字符不同,此时用指针 i 写入。重复该过程直至遍历完成。
class Solution {
public:
int compress(vector<char>& chars) {
int i(0), j(1);
char preChar = chars[0];
int count = 1;
string cstr;
while (j < chars.size()) {
if (preChar != chars[j]) {
chars[i++] = preChar;
if (count > 1) {
cstr = to_string(count);
for (int k = 0; k < cstr.size(); ++k) {
chars[i++] = cstr[k];
}
}
preChar = chars[j];
count = 1;
} else {
count++;
}
j++;
}
chars[i++] = preChar;
if (count > 1) {
cstr = to_string(count);
for (int k = 0; k < cstr.size(); ++k) {
chars[i++] = cstr[k];
}
}
return i;
}
};
算法时间复杂度为 O ( N ) O(N) O(N)
总结
用好双指针能够有效降低时间复杂度,简化问题。
本文介绍了如何利用双指针技巧解决LeetCode上的字符串处理问题,包括917题的字母反转、167题的两数之和、165题的版本号比较以及443题的字符串压缩。通过分析与解答,展示了双指针在优化算法时间复杂度方面的应用。
2093

被折叠的 条评论
为什么被折叠?



