1.反转字符(力扣344)
https://leetcode.cn/problems/reverse-string/description/
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题
利用i,j两个指针,i指向数组开头,j指向数组末尾,然后i不断往后走,与此同时j往前走,每移动一次位置,s[i]与s[j]就交换位置,直到i等于s.size()/2-1,即完成反转
代码如下:
点击查看代码
class Solution {
public:
void reverseString(vector<char>& s) {
int j = s.size() - 1;
for(int i = 0; i < s.size() / 2 ; i ++){
swap(s[i], s[j]);
j --;
}
}
};
2.移除元素(力扣27)
https://leetcode.cn/problems/remove-element/description/
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
对于样例:
输入:nums = [3,2,3,5,3], val = 3
输出:2, nums = [2,5]
数组3,2,3,5,3 对应的下标依次是0,1,2,3 而现在我们需要将3都删除,那么2的下标应该变为0,5的下标变为1,该过程的实现我们需要遍历数组,所以我们需要用到一个指针i,但是如何将与val相等的值删掉然后让数组的下标不变呢?那么就需要用到第二个指针j,如果遍历到的nums[i]等于val,j指针就不动,直到i指针指向的数不为val再将j指针指向的位置赋值为此时i指针的值,赋值结束后j指针加1,便实现了,元素的移除。总而言之,就是相等的跳过,不相等的依次赋值。
代码如下:
点击查看代码
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int j = 0;
for(int i = 0; i < nums.size(); i ++){
if(nums[i] != val){
nums[j ++] = nums[i];
}
}
return j;
}
};
3.删除有序数组中的重复项(力扣26)
https://leetcode.cn/problems/remove-duplicates-from-sorted-array/description/
给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。
考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:
- 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
- 返回 k 。
此道题和上述题目类似,我们先来看样例
输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
我的思路:可以用一个数组hash来记录nums数组中各个元素出现的次数,有i和j两个指针,如果hash[nums[i]]>0,那么说明该元素已经出现过了,j指针不动,i指针继续滑动,直到滑动到hash[nums[i]]=0时,将其赋值给j,然后j++,最后再返回j的值即可,但是不能出现新数组,我们只能在原数组做修改,所以做判断时也只能在原数组做。
于是,同样的,我们需要i和j两个指针,j指针用来保留当前元素,以样例1为例,最开始i与j都指向nums[0]即1,然后,i指针向后移动一个位置,nums[i]此时为nums[1],判断nums[1]与nums[j]即nums[0]是否相等,此时是相等的,我们不需要做额外的操作,只需将i指针往后移动,nums[i]此时为2,再与nums[j]即nums[0]作比较,不相等,那么就将此时的nums[i]的值赋给此时的nums[j]的下一个位置,即nums[++j],按照这个逻辑依次作判断,最后便可的删除所有重复元素啦,最后返回j+1,因为此时的j是下标
代码如下:
点击查看代码
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int j = 0;
for(int i = 0; i < nums.size(); i ++){
if(nums[j] != nums[i]){
nums[++j] = nums[i];
}
}
return j + 1;
}
};
4.移动零(力扣283)
https://leetcode.cn/problems/move-zeroes/description/
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
和2类似,即2中的val固定为0,相等跳过,不等赋值,不过最后还要将剩余的位置全部补为0
代码如下:
点击查看代码
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int j = 0;
for(int i = 0; i < nums.size(); i++){
if(nums[i] != 0){
nums[j ++] = nums[i];
}
}
for(int i = j; i < nums.size(); i++){
nums[i] = 0;
}
}
};
当然这道题还可以有另一种解法,即将整个数组一分为二,左边为不为0的数,右边为是0的数,这里的分界线就是0本身,与快速排序的思想类似
代码如下:
点击查看代码
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int j = 0;
for(int i = 0; i < nums.size(); i ++){
if(nums[i] != 0){
swap(nums[i], nums[j]);
j ++;
}
}
}
};
5.比较含退格的字符串(力扣844)
https://leetcode.cn/problems/backspace-string-compare/description/
给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。
注意:如果对空文本输入退格字符,文本继续为空。
这道题用字符串模拟栈就很好解,关于匹配的就可以考虑用栈的思想,即将输入的字符串重新依次赋值给一个新的字符串,如果遇到退格符,就将新字符串的末尾字符删去,代码如下:
点击查看代码
class Solution {
public:
bool backspaceCompare(string s, string t) {
string ss, tt;
for(int i = 0; i < s.size(); i ++){
if(s[i] != '#'){
ss += s[i];
}
else if(!ss.empty()) ss.pop_back();
}
for(int i = 0; i < t.size(); i ++){
if(t[i] != '#'){
tt += t[i];
}
else if(!tt.empty()) tt.pop_back();
}
if(ss != tt) return false;
else return true;
}
};
运用此解法踩的坑:一定要判断新字符串是否为空,如果没有这个判断就会运行错误。在string类中,删除末尾元素的函数即为pop_back()。
当然,这道题也可以用双指针来解,感觉这道题用双指针不是很好想,需要从后往前遍历,通过统计‘#’的数量然后用跳过元素的方法模拟删除操作然后逐一比较
代码如下:
点击查看代码
class Solution {
public:
bool backspaceCompare(string s, string t) {
int s_num = 0;//记录s的‘#’个数
int t_num = 0;//记录t的‘#’个数
int i = s.size() - 1;
int j = t.size() - 1;
while(1)
{
while(i >= 0){
if(s[i] == '#') s_num ++;
else{
//如果当前还有空格符,空格符数量减一
if(s_num > 0) s_num --;
//如果没有了,就退出循环进行比较
else break;
}
//跳过该元素表示删除
i --;
}
//t与s同理
while(j >= 0){
if(t[j] == '#') t_num ++;
else{
if(t_num > 0) t_num --;
else break;
}
j --;
}
//首先判断s与t是否有遍历到头的,如果二者有一个遍历到头的,就退出循环
if(i < 0 || j < 0) break;
//都没有遍历到头就比较当前的字符,如果不相等,就直接返回假
if(s[i] != t[j]) return false;
//比较完以后记得两个字符串都向前挪一个位置
i--;j--;//这一步很重要!!!!
}
//如果二者同时遍历到头,则说明相等
if(i < 0 && j < 0) return true;
//否则,为假
else return false;
}
};
6.替换数字
https://kamacoder.com/problempage.php?pid=1064
给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。 例如,对于输入字符串 "a1b2c3",函数应该将其转换为 "anumberbnumbercnumber"。
首先统计该字符串中含有多少个数字,记为count,然后将该字符串扩展为count*5+原长度,运用resize函数进行扩展,然后再从后往前遍历字符串,如果该字符为数字,则倒序将number存入字符串中
其实很多数组填充类的问题,其做法都是先预先给数组扩容带填充后的大小,然后在从后向前进行操作。
这么做有两个好处:
- 不用申请新数组。
- 从后向前填充元素,避免了从前向后填充元素时,每次添加元素都要将添加元素之后的所有元素向后移动的问题。
代码如下:
点击查看代码
# include<iostream>
# include<algorithm>
using namespace std;
# include<string>
const int N = 10010;
int main(){
string s;
cin >> s;
int count = 0;
int sOldsize = s.size();
for(int i = 0; i < s.size(); i++ ){
if(s[i] <= '9' && s[i] >= '0'){
count++;
}
}
s.resize(s.size() + count * 5);
int sNewsize = s.size();
int j = sNewsize - 1;
for(int i = sOldsize - 1; i >= 0; i--){
if(s[i] <= '9' && s[i] >= '0'){
s[j] = 'r';
s[j - 1] = 'e';
s[j - 2] = 'b';
s[j - 3] = 'm';
s[j - 4] = 'u';
s[j - 5] = 'n';
j = j - 5;
}
else {
s[j] = s[i];
}
j--;
}
cout << s;
return 0;
}