题目列表:167、633、345、680、88、141、524

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

给定一个已按照升序排列的有序数组,找到两个数使得它们相加之和等于目标数。函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
示例:
输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。

题解思路:
使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。

  • 如果两个指针指向元素的和 sum == target,那么得到要求的结果;
  • 如果 sum > target,移动较大的元素,使 sum 变小一些;
  • 如果 sum < target,移动较小的元素,使 sum 变大一些。
    1. public int[] twoSum(int[] numbers, int target) {
    2. if (numbers == null) return null;
    3. int i = 0, j = numbers.length - 1;
    4. while (i < j) {
    5. int sum = numbers[i] + numbers[j];
    6. if (sum == target) {
    7. return new int[]{i + 1, j + 1};
    8. } else if (sum < target) {
    9. i++;
    10. } else {
    11. j--;
    12. }
    13. }
    14. return null;
    15. }

633. 平方数之和

给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a平方 + b平方 = c 。
示例 1:
输入:c = 5
输出:true
解释:1 1 + 2 2 = 5
class Solution {
    public boolean judgeSquareSum(int c) {
        int a=0;
        int b=(int)Math.sqrt(c);
        while(a<=b){
            int num=a*a+b*b;
            if(num==c){
                return true;
            }else if(num>c){
                b--;
            }else if(num<c){
                a++;
            }
        }
        return false;
    }
}

关键点:在于如何确定右指针的位置,如果将右指针的位置置于c,将会出现整型溢出的情况,改用long解决溢出问题,同样回出现超时的情况。

345. 反转字符串中的元音字母

编写一个函数,以字符串作为输入,反转该字符串中的元音字母。

 public String reverseVowels(String s) {
        char[] c = s.toCharArray();
        int l = 0;
        int r = c.length - 1;
        while (l < r) {
            if (!vertify(c[l])) {
                l++;
                continue;
            }
            if (!vertify(c[r])) {
                r--;
                continue;
            }
            char c1=' ';
            c1 = c[l];
            c[l++] = c[r];
            c[r--] = c1;
        }
        String s1=new String(c);
        return s1;
    }

    //判断是否为元音字母
    public boolean vertify(char c) {
        return (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u'||c=='A'||c=='E'||c=='I'||c=='O'||c=='U');
    }
题解思路:
1、依旧是碰撞指针的思想,两边向中间操作,判断是否为元音字母,不是就移动指针,直到是开始交换。
           while (!vertify(c[l])) {
                l++;
            }
            while (!vertify(c[r])) {
                r--;
            }
            if(l<r){            //这一步判断是一定要做的
                char c1 = ' ';
                c1 = c[l];
                c[l++] = c[r];
                c[r--] = c1;
            }

中间的判断逻辑可以通过while循环来完成,但是后面一定要加上左右值的判断,不然原先替换好的值会被替换回去。

680. 验证回文字符串 Ⅱ

给定一个非空字符串 s最多删除一个字符。判断是否能成为回文字符串。
示例 1:
输入: “aba”
输出: True

所谓回文数就是指具有左右对称特点的字符串

使用双指针可以很容易判断一个字符串是否是回文字符串:令一个指针从左到右遍历,一个指针从右到左遍历,这两个指针同时移动一个位置,每次都判断两个指针指向的字符是否相同,如果都相同,字符串才是具有左右对称性质的回文字符串。

此题的题设相当于给予了左右指针多一次的机会。但是可能存在的删除左边或者是删除右边的情况,如果使用一个标识位来做判断的话就会显得比较的麻烦。因此我们可以考虑在提取出判断的方法,重新定义需要判断的长度

public boolean validPalindrome(String s) {
    for (int i = 0, j = s.length() - 1; i < j; i++, j--) {
        if (s.charAt(i) != s.charAt(j)) {
            //考虑左右两种情况,任意一种情况满足条件即可。
            return isPalindrome(s, i, j - 1) || isPalindrome(s, i + 1, j);
        }
    }
    return true;
}

private boolean isPalindrome(String s, int i, int j) {
    while (i < j) {
        if (s.charAt(i++) != s.charAt(j--)) {
            return false;
        }
    }
    return true;
}

88. 合并两个有序数组

//给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
class Solution {
  public void merge(int[] nums1, int m, int[] nums2, int n) {
        int ai = m + n - 1;
        int mi = m - 1;
        int ni = n - 1;
        while (ni >= 0) {
            if (mi >= 0 && nums1[mi] > nums2[ni]) {
                nums1[ai--] = nums1[mi--];
            } else {
                nums1[ai--] = nums2[ni--];
            }
        }
    }
}
题解思路:(倒序处理)
1、题目给出了每个数组的实际有效长度,所以不要被后面的0所迷惑
2、数组1的有效长度为m,数组2的有效长度为n,所以其实真正有效的数组长度为m+n
3、因此我们只需要在nums数组长度为m+n的区间内操作即可,两数组的数进行比较,大的数放进数组
4、注意while和if中的边界条件

哪个数组赋值给长数组了,就移动哪一个。

141. 环形链表

题解思路:双指针,慢指针走一步,快指针走两步

public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head==null){
            return false;
        }

        ListNode slow=head;
        ListNode fast=head.next;
        while(slow!=null&&fast!=null&&fast.next!=null){
            if(slow==fast){
                return true;
            }
            slow=slow.next;
            fast=fast.next.next;
        }
        return false;
    }
}

**

524. 通过删除字母匹配到字典里最长单词

给定一个字符串和一个字符串字典,找到字典里面最长的字符串,该字符串可以通过删除给定字符串的某些字符来得到。如果答案不止一个,返回长度最长且字典顺序最小的字符串。如果答案不存在,则返回空字符串。
示例 1:
输入:s = “abpcplea”, d = [“ale”,”apple”,”monkey”,”plea”]
输出:“apple”
class Solution {
    public String findLongestWord(String s, List<String> d) {
        String longest = "";
        for (String target : d) {
            int x = longest.length(), y = target.length();
            //此处的longestcompareTo保证字典顺序
            if (x > y || (x == y && longest.compareTo(target) < 0)) {        *
                continue;
            } else if (isSubString(s, target)) {
                longest = target;
            }
        }
        return longest;
    }

    private boolean isSubString(String s, String target) {
        int i = 0, j = 0;
        while (i < s.length() && j < target.length()) {
            if (s.charAt(i) == target.charAt(j)) {
                j++;
            }
            i++;
        }
        return j == target.length();
    }
}

注意点:初始筛选条件我写的是 if (x >= y ) { continue; },但是这种写法是没有办法保证得到的结果满足字典顺序最小的条件

125. 验证回文串

  • 空字符串如何看?
  • 字符的定义?
  • 大小写问题 ```java class Solution { public boolean isPalindrome(String s) {

      int left = 0;
      int right = s.length() - 1;
      char[] c = s.toCharArray();
      while (left < right) {
          if (!vertify(c[left])) {
              left++;
              continue;
          }
          if (!vertify(c[right])) {
              right--;
              continue;
          }
          if (toLowercase(c[left]) != toLowercase(c[right])) {
              return false;
          }
          left++;
          right--;
      }
      return true;
    

    }

    //判断是否为字符或者是数字 public boolean vertify(char c) {

      return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
    

    }

    //字符大写转小写 public char toLowercase(char c) {

      if (c >= 'A' && c <= 'Z') {
          c += 32;
      }
      return c;
    

    } }

| 题解思路:<br />1、判断回文数依旧可以考虑指针碰撞的方式解决。<br />2、关键在于判断之前要先处理大小写问题,以及除数字以及字母外的问题。<br />[字符可以直接通过字符之间比较,无需去考虑ASCII的值大小] |
| --- |


```java
class Solution {
 public boolean isPalindrome(String s) {
        if (null == s) {
            return false;
        }
        if (s.length() == 0) {
            return true;
        }
        s = s.replaceAll("[^a-zA-Z0-9]", "");
        String reverse = String.valueOf(new StringBuilder(s).reverse());
        return s.equalsIgnoreCase(reverse);
    }
}
题解思路:
1、使用正则表达式替换无关符号
2、通过StringBuilder的反转功能
3、通过String的忽略大小写比较功能

11. 盛最多水的容器

给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
1、双指针 - 图1

class Solution {
    public int maxArea(int[] height) {
        int l = 0;
        int r = height.length - 1;
        int h;//代表高度
        int length;//代表长度

        int area = 0;//代表面积

        boolean flag = true;//标志位,下一次循环应该谁移动

        while(l<r){
            h = height[l] > height[r] ? height[r] : height[l];
            length = r - l;
            area = (h * length) > area ? (h * length) : area;
            if(height[l]>height[r]){
                r--;
            }else{
                l++;
            }
        }
         return area;
    }
题解思路:
1、一开始使用了双层嵌套循环的方式处理,但是耗时太长了
2、错误的处理步骤中,移动的方式是左移一步然后右移一步
3、正确的方式应该是哪边小就应该是哪边移动,这个思想和167号题是类似的

对O(n)的算法写一下自己的理解,一开始两个指针一个指向开头一个指向结尾,此时容器的底是最大的,接下来随着指针向内移动,会造成容器的底变小,在这种情况下想要让容器盛水变多,就只有在容器的高上下功夫。 那我们该如何决策哪个指针移动呢?我们能够发现不管是左指针向右移动一位,还是右指针向左移动一位,容器的底都是一样的,都比原来减少了 1。这种情况下我们想要让指针移动后的容器面积增大,就要使移动后的容器的高尽量大,所以我们选择指针所指的高较小的那个指针进行移动,这样我们就保留了容器较高的那条边,放弃了较小的那条边,以获得有更高的边的机会。