【双指针、滑动窗口、矩阵】算法例题

目录

 二、双指针

25. 验证回文数 ①

26. 判断子序列 ①

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

28. 盛最多水的容器 ②

29. 三数之和 ②

 三、滑动窗口

30. 长度最小的子数组 ②

31. 无重复字符的最长子串 ②

32. 串联所有单词的子串 ③

33. 最小覆盖子串 ③

四、矩阵

34. 有效的数独 ②

35. 螺旋矩阵 ②

36. 旋转图像 ②

37. 矩阵置零 ②

38. 生命游戏 ②



 二、双指针

25. 验证回文数 ①

 如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。

字母和数字都属于字母数字字符。

给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false 

    示例 1:

    输入: s = "A man, a plan, a canal: Panama"
    输出:true
    解释:"amanaplanacanalpanama" 是回文串。
    示例 2:

    输入:s = "race a car"
    输出:false
    解释:"raceacar" 不是回文串。
    示例 3:

    输入:s = " "
    输出:true
    解释:在移除非字母数字字符之后,s 是一个空字符串 "" 。
    由于空字符串正着反着读都一样,所以是回文串。


    提示:

    1 <= s.length <= 2 * 105
    s 仅由可打印的 ASCII 字符组成

    方法1:

        public static boolean isPalindrome(String s) {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);
                if (Character.isUpperCase(c)){
                    c = Character.toLowerCase(c);
                }
                if (Character.isLowerCase(c) || Character.isDigit(c)){
                    stringBuilder.append(c);
                }
            }
    //        比较的时候要把stringBuilder放左边
    //        因为stringBuilder.reverse()会改变stringBuilder的值
            if (stringBuilder.toString().equals("") || stringBuilder.toString().equals(stringBuilder.reverse().toString())){
                return true;
            }else {
                return false;
            }
        }

    方法2:

        public boolean isPalindrome(String s) {
            int first = 0;
            int last = s.length() - 1;
            char[] chars = s.toCharArray();
            while (first < last) {
                if(chars[first] < 48 || (chars[first] > 57 && chars[first] < 65) || (chars[first] > 90 && chars[first] < 97) || chars[first] > 122) {
                    first++;
                    continue;
                }
                if(chars[last] < 48 || (chars[last] > 57 && chars[last] < 65) || (chars[last] > 90 && chars[last] < 97) || chars[last] > 122) {
                    last--;
                    continue;
                }
                if(chars[first] < 97) chars[first] += 32;
                if(chars[last] < 97) chars[last] += 32;
                if(chars[first] != chars[last]) return false;
                first++;
                last--;
            }
            return true;
        }

    26. 判断子序列 ①

     给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

    字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace""abcde"的一个子序列,而"aec"不是)。

    进阶:

    如果有大量输入的 S,称作 S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?

    致谢:

    特别感谢 @pbrother 添加此问题并且创建所有测试用例。

      示例 1:

      输入:s = "abc", t = "ahbgdc"
      输出:true
      示例 2:

      输入:s = "axc", t = "ahbgdc"
      输出:false


      提示:

      0 <= s.length <= 100
      0 <= t.length <= 10^4
      两个字符串都只由小写字符组成。

      方法1(2ms)

          public boolean isSubsequence(String s, String t) {
              int small = 0;
              for (int i = 0; i < t.length(); i++) {
                  if (small < s.length() && t.charAt(i) == s.charAt(small)){
                      small++;
                  }
              }
              if (small == s.length()){
                  return true;
              }else {
                  return false;
              }
          }
          public boolean isSubsequence(String s, String t) {
              int i = 0, j = 0;
              while (i < s.length() && j < t.length()) {
                  if (s.charAt(i) == t.charAt(j)){
                      i++;
                  }
                  j++;
              }
              return i == s.length();
          }

      方法2:(0ms)

          public boolean isSubsequence(String s, String t) {//运用数组和String API
              int index=-1;
              for(char ch:s.toCharArray()){
                  index=t.indexOf(ch,index+1);
                  if(index==-1){
                      return false;
                  }
              }
              return true;
          }

      27. 两数之和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
      仅存在一个有效答案

        方法1:(447ms)

            public int[] twoSum(int[] numbers, int target) {
                int[] result = new int[2];
                for (int i = 0; i < numbers.length; i++) {
                    for (int j = numbers.length - 1; j > i; j--) {
                        if (numbers[j] == target - numbers[i]){
                             result[0] = i + 1;
                             result[1] = j + 1;
                             return result;
                        }
                    }
                }
                return result;
            }

        (1ms)

            public int[] twoSum(int[] numbers, int target) {
                int[] result = new int[2];
                int left = 0;
                int right = numbers.length - 1;
                while (true){
                    if (numbers[left] + numbers[right] > target){
                        right--;
                    }else if (numbers[left] + numbers[right] < target){
                        left++;
                    }else {
                        result[0] = left + 1;
                        result[1] = right + 1;
                        return result;
                    }
                }
            }

        28. 盛最多水的容器 ②

         给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

        找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

        返回容器可以储存的最大水量。

        说明:你不能倾斜容器。

        示例 1:

        输入:[1,8,6,2,5,4,8,3,7]
        输出:49 
        解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
        示例 2:
        
        输入:height = [1,1]
        输出:1
        
        
        提示:
        
        n == height.length
        2 <= n <= 105
        0 <= height[i] <= 104
        

          方法1:(3ms)

              public static int maxArea(int[] height) {
                  int left = 0;
                  int right = height.length - 1;
                  int area = 0;
                  while (left < right){
                      int min = Math.min(height[left], height[right]);
                      if (min * (right - left) > area){
                          area = min * (right - left);
                      }
                      if (min == height[left]){
                          left++;
                      }else {
                          right--;
                      }
                  }
                  return area;
              }

          方法2:(1ms)

              public int maxArea(int[] height) {
                  int l = 0;
                  int r = height.length-1;
                  int max = 0;
                  int minH;
                  while(l<r){
                      minH = Math.min(height[l],height[r]);
                      max = Math.max(max,minH*(r-
          评论
          添加红包

          请填写红包祝福语或标题

          红包个数最小为10个

          红包金额最低5元

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

          抵扣说明:

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

          余额充值