7月算法训练------第五天(双指针)解题报告

7月算法训练------第五天(双指针)解题报告

题目类型:双指针
题目难度:简单

第一题、392. 判断子序列

  • 题目链接:392. 判断子序列

  • 思路分析:
    我们先将字符串s转为字符数组chs,定义一个index变量,表示从字符串t的第index位找chs中的字符;
    然后遍历字符串t,在t中找chs[i],找到chs[i],就更新index的值;
    如果没找到,就返回false
    每次循环完,使index++,表示下一次从index+1位开始找chs[i]
    如果都能找到,则返回true。

  • 需要用到java.lang.String类中的indexOf()方法:

返回值方法名方法作用
intindexOf(String str, int fromIndex)返回此字符串的指定子字符串中第一个出现在索引中,从指定索引处开始。

代码:

class Solution {
    public boolean isSubsequence(String s, String t) {
        char[] chs = s.toCharArray();
        // char[] cht = t.toCharArray();
        int index = 0;
        for(int i = 0; i < chs.length; i++){
            index = t.indexOf(chs[i], index);
            if(index == -1){
                return false;
            }
            index++;
        }
        return true;
    }
}

第二题、

  1. 题目链接:541. 反转字符串 II
  2. 思路分析:
  • 以题目中的例子:"abcdefg"2
  • 我们分析发现,这一题就是让这个字符串的某一部分反转,而这个子串满足它是这个字符串的每2k个序列的前k个,我们可以用每k个字符串划分为一组子串的形式:
  • 要划分的字符串:
0123456
abcdefg
  • 先将这个字符串按每k(这里k=2)位为一组划分,这里要注意如何精确地计算出要申请的字符串数组strCh的长度是多少:
strCh[0]strCh[1]strCh[2]strCh[3]
abcdefg
  • 然后我们找出要反转的子串,这里我们需要注意怎样找到数组中的要反转的那一组:
strCh[0]strCh[1]strCh[2]strCh[3]
bacdfeg

红色标注就是我们要反转的字符串。

  • 需要用到的知识:

java.lang.String类中截取子字符串的方法substring(int beginIndex, int endIndex)

返回类型方法名方法功能
Stringsubstring(int beginIndex, int endIndex)返回一个字符串,这个字符串的子串。
Stringsubstring(int beginIndex)返回一个字符串,这个字符串的子串。

java.lang.StringBuilder中反转字符串的方法reverse()

  1. 代码:
class Solution {
    public String reverseStr(String s, int k) {
        String[] strCh; //srtCh的长度由s的长度与k决定
        int mark = 0; //用来辅助计算循环次数
        if(s.length() % k == 0){
            strCh = new String[s.length() / k];
            mark = s.length() / k;
        }else{
            strCh = new String[s.length() / k + 1];
            mark = s.length() / k + 1;
        }
        for(int i = k; i <= k * mark; i += k){
            if(i < s.length()){
                StringBuilder sb = new StringBuilder(s.substring(i-k, i));
                if((i / k) % 2 == 1){
                    sb.reverse();
                }
                strCh[i / k - 1] = sb.toString();
            }else{
                StringBuilder sb = new StringBuilder(s.substring(i-k, s.length()));
                if((i / k) % 2 == 1){
                    sb.reverse();
                }
                strCh[i / k - 1] = sb.toString();
            }
        }
        StringBuilder sb2 = new StringBuilder();
        for(int i = 0; i < strCh.length; i++){
            sb2.append(strCh[i]);
        }
        return sb2.toString();
    }
}

第三题、面试题 16.24. 数对和

  1. 题目链接:面试题 16.24. 数对和
  2. 思路分析:
  • 看到这一题,我们要向用双指针做,首先要对数组排序;
    这一题比较简单,要求的是每组是两个数:
  • 我们先定义一个左指针l=0和右指针r=nums.length
    • nums[l] + nums[r] == target时,我们将nums[l]nums[r]都放入定义好的ArrayList lint中,然后将l++l向右移)和r--r向左移);
    • nums[l] + nums[r] > target时,说明此时需要将两数之和变小,而只有r向右移时,两数之和在变小,所以只将r--
    • nums[l] + nums[r] < target时,说明此时需要将两数之和变大,而只有l向左移时,两数之和在变大,所以只将l++
  1. 代码:
class Solution {
    public List<List<Integer>> pairSums(int[] nums, int target) {
        Arrays.sort(nums);
        List<List<Integer>> llist = new ArrayList();
        int l = 0, r = nums.length - 1;
        while(r > l){
            List<Integer> lint = new ArrayList();
            if(nums[l] + nums[r] == target){
                lint.add(nums[l]);
                lint.add(nums[r]);
                llist.add(lint);
                l++;
                r--;
            }else if(nums[l] + nums[r] > target){
                r--;
            }else{
                l++;
            }
        }
        return llist;
    }
}

第四题、696. 计数二进制子串

题目链接:696. 计数二进制子串
思路分析:

  • 暴力解法:
    时间复杂度O(N^2)
    我们用一个数来表示当前的得分score,当我们遇见0时,得分减一,当我们遇见1时,得分加一;
    当得分等于0时,我们就将结果num加一;
    为了控制01是连续的,当我们遍历的当前循环第一位是0 &&j-1位是1 &&j位是0
    当我们遍历的当前循环第一位是1 &&j-1位是0 &&j位是1时,这两种情况都是不连续的情况,所以直接舍弃;
    为了保证上面的情况成立,得分score的初值也由当前循环第一位决定;
    当前循环第一位是0时,score=-1
    当前循环第一位是1时,score=0
    但这种方法时间复杂度过高,不能通过;
    暴力代码:
class Solution { 
    public int countBinarySubstrings(String s) {
        char[] ch = s.toCharArray();
        int score = 0, num = 0;
        for(int i = 0; i < s.length(); i++){
            if(ch[i] == '0'){
                score = -1;
            }else{
                score = 1;
            }
            for(int j = i+1; j < s.length(); j++){
                if(ch[i] == '0' && ch[j - 1] == '1' && ch[j] == '0'){
                    break;
                }
                if(ch[i] == '1' && ch[j - 1] == '0' && ch[j] == '1'){
                    break;
                }
                if(ch[j] == '0'){
                    score-=1;
                }else{
                    score+=1;
                }
                if(score == 0){
                    num++;
                    break;
                }
            }

        }
        return num;
    }
}

只能另想一种时间复杂度低的方法:看了答案很受启发,答案确实牛批:
比如我们输入字符串为:“11011100”;
我们先让它变成一个数组,数组变换方法是:
拿例子说:现有2个"1",将2入alist;
然后有1个"0",将1入alist;
然后有3个"1",将3入alist;
然后有2个"0",将2入alist。

最后的数组就是:{2,1,3,2};
每两个相邻的数求最小值,累加就是答案了:
{2,1}的最小值是1,加1;
{1,3}的最小值是1,加1;
{3,2}的最小值是2,加2。

最终值为4。

代码:

class Solution {
    public int countBinarySubstrings(String s) {
        List<Integer> alist = new ArrayList();
        int ptr = 0, n = s.length();
        while(ptr < n){
            char c = s.charAt(ptr);
            int count = 0;
            while(ptr < n && s.charAt(ptr) == c){
                count++;
                ptr++;
            }
            alist.add(count);
        }
        int ans = 0;
        for(int i = 1; i < alist.size(); i++){
            ans += Math.min(alist.get(i), alist.get(i-1));
        }
        return ans;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值