算法专练:双指针

1.917. 仅仅反转字母

原题链接

        给你一个字符串 s ,根据下述规则反转字符串:

        所有非英文字母保留在原有位置。

        所有英文字母(小写或大写)位置反转。

        返回反转后的 s
示例 1:
输入:s = “ab-cd”
输出:“dc-ba”
示例 2:
输入:s = “a-bC-dEf-ghIj”
输出:“j-Ih-gfE-dCba”
示例 3:
输入:s = “Test1ng-Leet=code-Q!”
输出:“Qedo1ct-eeLg=ntse-T!”
提示
1 <= s.length <= 100
s 仅由 ASCII 值在范围 [33, 122] 的字符组成
s 不含 ‘"’ 或 ‘\’


        利用双指针每次分别找到两边第一个字母然后交换即可.

class Solution {
        bool ischar(char c){
            return c>='a'&&c<='z'||c>='A'&&c<='Z';
        }
public:
    string reverseOnlyLetters(string s) {
        int left=0,right=s.length()-1;
        while(left<right)
        {
            while(left<right&&!ischar(s[right]))
            right--;
            while(left<right&&!ischar(s[left]))
            left++;
            if(left>=right)
            break;
            swap(s[left++],s[right--]);
        }
        return s;
    }
};

2.167. 两数之和 II - 输入有序数组

原题链接


        给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。

        以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。

        你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

        你所设计的解决方案必须只使用常量级的额外空间。
示例 1:
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
示例 2:
输入:numbers = [2,3,4], target = 6
输出:[1,3]
解释:2 与 4 之和等于目标数 6 。因此 index1 = 1, index2 = 3 。返回 [1, 3] 。
示例 3:
输入:numbers = [-1,0], target = -1
输出:[1,2]
解释:-1 与 0 之和等于目标数 -1 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
提示:
2 <= numbers.length <= 3 * 104
-1000 <= numbers[i] <= 1000
numbers 按 非递减顺序 排列
-1000 <= target <= 1000
仅存在一个有效答案


        两数之和的变形,也就是要我们找到这两个数的下标,这道题可以用二分,不过这篇文章叫双指针就用双指针了,也是在两边扫描,因为数组非递减,那么如果当前两数之和大于target右指针往前走,如果小于左指针向后走,否则直接返回当前两个下标的集合。不过观察示例,发现它的下标是按照1开始的,所以最后答案的下标要分别加1.

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int l=0,r=numbers.size()-1;
        while(l<=r){
            int sum=numbers[l]+numbers[r];
            if(sum==target){
                return {l+1,r+1};
            }else if(sum>target){
                r--;
            }else l++;
        }
        return {};
    }
};

3.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。
示例 1:
输入:version1 = “1.01”, version2 = “1.001”
输出:0
解释:忽略前导零,“01” 和 “001” 都表示相同的整数 “1”
示例 2:
输入:version1 = “1.0”, version2 = “1.0.0”
输出:0
解释:version1 没有指定下标为 2 的修订号,即视为 “0”
示例 3:
输入:version1 = “0.1”, version2 = “1.1”
输出:-1
解释:version1 中下标为 0 的修订号是 “0”,version2 中下标为 0 的修订号是 “1” 。0 < 1,所以 version1 < version2
提示:
1 <= version1.length, version2.length <= 500
version1 和 version2 仅包含数字和 ‘.’
version1 和 version2 都是 有效版本号
version1 和 version2 的所有修订号都可以存储在 32 位整数 中


        首先将给定的两个字符串按照 ’ . ’ 进行分割为若干个字符串,分别表示每个修订号。如果两个字符串分割后字符串数量不等,就代表数量小的那个字符串的这个修订号为0.

        切割之后开始比较每个修订号,如果其中出现了不相等的情况,直接返回1或者-1,直到所有修订号都比较完后返回0。

        那么如何比较呢?我们只需要把需要比较的字符串看成一个数字即可。如果长度不等,自然是长度相等的大,如果不相等就按照strcmp来比较。不过strcmp的返回值我在这里并不清楚编译器的返回值是什么就自己重写了。

class Solution {
    vector<string> ret;
    vector<string> splitAllPoint(string  s){
        ret.clear();
        string tmp;
        s.push_back('.');//为了使得最后一个修订号也能加入
        for(int i=0;i<s.size();++i){
            if(s[i]=='.'){
                if(tmp.size()==0){
                    tmp="0";//这里代表连续的.,那么在这些.之间的修订号为0
                }
                ret.push_back(tmp);
                tmp="";
            }else {
                if(s[i]=='0'){
                    if(tmp.size()){
                        tmp.push_back(s[i]);//代表此时不是前导零
                    }
                }else {
                    tmp.push_back(s[i]);
                }
            }
        }
        return ret;
    }
    int  cmpar(string s1,string s2){
        int size1=s1.size();
        int size2=s2.size();
        if(size1!=size2){
            return size1<size2?-1:1;
        }
        if(s1==s2){
            return 0;
        }
        return s1<s2?-1:1;
    }
public:
    int compareVersion(string version1, string version2) {
        vector<string> s1=splitAllPoint(version1);
        vector<string> s2=splitAllPoint(version2);
        while(s1.size()<s2.size()) s1.push_back("0");
        while(s2.size()<s1.size()) s2.push_back("0");
        for(int i=0;i<s1.size();++i){
            int ans=cmpar(s1[i],s2[i]);
            if(ans){
                return ans;
            }
        }
        return 0;
    }
};

4.443. 压缩字符串

原题链接


        给你一个字符数组 chars ,请使用下述算法压缩:

        从一个空字符串 s 开始。对于 chars 中的每组 连续重复字符 :

        如果这一组长度为 1 ,则将字符追加到 s 中。

        否则,需要向 s 追加字符,后跟这一组的长度。

        压缩后得到的字符串 s 不应该直接返回 ,需要转储到字符数组 chars 中。需要注意的是,如果组长度为 10 或 10 以上,则在 chars 数组中会被拆分为多个字符。

        请在 修改完输入数组后 ,返回该数组的新长度。

        你必须设计并实现一个只使用常量额外空间的算法来解决此问题。
示例 1:
输入:chars = [“a”,“a”,“b”,“b”,“c”,“c”,“c”]
输出:返回 6 ,输入数组的前 6 个字符应该是:[“a”,“2”,“b”,“2”,“c”,“3”]
解释:“aa” 被 “a2” 替代。“bb” 被 “b2” 替代。“ccc” 被 “c3” 替代。
示例 2:
输入:chars = [“a”]
输出:返回 1 ,输入数组的前 1 个字符应该是:[“a”]
解释:唯一的组是“a”,它保持未压缩,因为它是一个字符。
示例 3:
输入:chars = [“a”,“b”,“b”,“b”,“b”,“b”,“b”,“b”,“b”,“b”,“b”,“b”,“b”]
输出:返回 4 ,输入数组的前 4 个字符应该是:[“a”,“b”,“1”,“2”]。
解释:由于字符 “a” 不重复,所以不会被压缩。“bbbbbbbbbbbb” 被 “b12” 替代。
提示:
1 <= chars.length <= 2000
chars[i] 可以是小写英文字母、大写英文字母、数字或符号


        这个相对来说比较简单,按照题意模拟即可。

class Solution {
public:
    int compress(vector<char>& chars) {
        int cnt=1;
        string help;
        chars.push_back('~');//在原字符串末尾加一个不属于题目字符范围内的字符主要目的是为了处理最后一个字符
        char c=chars[0];
        for(int i=1;i<chars.size();++i){
            if(chars[i]==c){
                cnt++;
            }else{
                help+=c;
                if(cnt>1){
                    stringstream ss;
                    ss<<cnt;
                    help+=ss.str();
                }                                 //  (1)
                c=chars[i];
                cnt=1;
            }
        }
        for(int i=0;i<help.size();++i){
            chars[i]=help[i];
        }
        return help.size();
    }
};

这里解释一下(1),其实主要原因是我懒得写把数字转成字符串了了所以借助了stringstream来操纵,这一步就是把cnt读到ss中去然后再把ss的数据转成字符。比如有132个a,ss里面就读入了132.而stringstream中有一个函数.str(),可以将其中的缓冲释放并返回到一个临时的string中,所以这里可以借助ss.str()把132转化为"132"最后再把help赋值给chars即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值