Leetcode刷题之路(一)(双指针)

#167 两数之和

我的解法:

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        if(numbers == null) return null;
        int i=0, j=numbers.length-1;
        while(i<j){
            int sum = numbers[i]+numbers[j];
            if(sum == target){
                return new int[]{i+1, j+1};
            } else if(sum < target){
                i++;
            }else{
                j--;
            }
        }
        return null;
    }
}

标准解法:

public int[] twoSum(int[] numbers, int target) {
    if (numbers == null) return null;
    int i = 0, j = numbers.length - 1;
    while (i < j) {
        int sum = numbers[i] + numbers[j];
        if (sum == target) {
            return new int[]{i + 1, j + 1};
        } else if (sum < target) {
            i++;
        } else {
            j--;
        }
    }
    return null;
}

注意点:

  1. 输出序号比index多1
  2. 指针i++,j–
  3. 可以直接返回一个新数组 return new int[]{i + 1, j + 1};
  4. 数组中的元素最多遍历一次,时间复杂度为O(n),只用了两个额外变量,空间复杂度为O(1)

#633 平方数之和

我的解法:

 public boolean judgeSquareSum(int c) {
        int a=0;
        int b=(int)Math.sqrt(c);
        int sum = 0;
        while(sum != c){
            sum = a*a+b*b;
            if(b == Math.sqrt(c)){
                return true;
            }else if(sum == c){
                return true;
            }else if(sum>c){
                b--;
            }else if(sum<c){
                a++;
            }else if(a>b){
                return false;
            }
        }
        return false;
    }

标准解法:

 public boolean judgeSquareSum(int target) {
     if (target < 0) return false;
     int i = 0, j = (int) Math.sqrt(target);
     while (i <= j) {
         int powSum = i * i + j * j;
         if (powSum == target) {
             return true;
         } else if (powSum > target) {
             j--;
         } else {
             i++;
         }
     }
     return false;
 }

本题的关键是右指针的初始化,实现剪枝,从而降低时间复杂度。设右指针为 x,左指针固定为 0,为了使 02 + x2 的值尽可能接近 target,我们可以将 x 取为 sqrt(target)。

因为最多只需要遍历一次 0~sqrt(target),所以时间复杂度为 O(sqrt(target))。又因为只使用了两个额外的变量,因此空间复杂度为 O(1)。

注意点:

  1. j = (int) Math.sqrt(target)。调用开平方函数并用(int)强转成整型。
  2. 判断循环是否继续进行的标志用while (i <= j)更好。
  3. 首先要判断target是否小于0。if (target < 0) return false;

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

我的解法:

class Solution {
    public String reverseVowels(String s) {
        HashSet<String> sites = new HashSet<String>();
        sites.add("a");
        sites.add("o");
        sites.add("e");
        sites.add("i");
        sites.add("u");
        sites.add("A");
        sites.add("O");
        sites.add("E");
        sites.add("I");
        sites.add("U");
        if(s == null) return null;
        int i=0, j=s.length()-1;
        char[] result = new char[s.length()];
        while(i<j){
            char si = s.charAt(i);
            char sj = s.charAt(j);
            if(!sites.contains(si)){
                result[i++]=si;
            }else if(!sites.contains(sj)){
                 result[j--]=sj;
            }else{
                result[i++]=sj;
                result[j--]=si;
            }
        }
        return new String(result);
    }
}

标准解法:

private final static HashSet<Character> vowels = new HashSet<>(
        Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));

public String reverseVowels(String s) {
    if (s == null) return null;
    int i = 0, j = s.length() - 1;
    char[] result = new char[s.length()];
    while (i <= j) {
        char ci = s.charAt(i);
        char cj = s.charAt(j);
        if (!vowels.contains(ci)) {
            result[i++] = ci;
        } else if (!vowels.contains(cj)) {
            result[j--] = cj;
        } else {
            result[i++] = cj;
            result[j--] = ci;
        }
    }
    return new String(result);
}

注意点:

  1. HashSet的使用
  2. 双指针的使用

#680 回文字符串

本题初次做时没有思路,只想到了先完成证明是普通回文字符串的方法。
标准解法

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. 合并两个有序数组

我的解法:

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        for(int i=n-1; i>=0; i--){
            for(int j=m-1, k=m+n-1; j>=0; j--){
                if(nums2[i]>nums1[j]){
                    nums1[k--]=nums2[i--];
                }else {
                    nums1[k--]=nums1[j];
                }
            }
        }
    }
}

标准解法:

public void merge(int[] nums1, int m, int[] nums2, int n) {
    int index1 = m - 1, index2 = n - 1;
    int indexMerge = m + n - 1;
    while (index2 >= 0) {
        if (index1 < 0) {
            nums1[indexMerge--] = nums2[index2--];
        } else if (index2 < 0) {
            nums1[indexMerge--] = nums1[index1--];
        } else if (nums1[index1] > nums2[index2]) {
            nums1[indexMerge--] = nums1[index1--];
        } else {
            nums1[indexMerge--] = nums2[index2--];
        }
    }
}

注意点:

  1. 需要从尾开始遍历,否则在 nums1 上归并得到的值会覆盖还未进行归并比较的值。

#141 判断链表中是否存在环

public boolean hasCycle(ListNode head) {
    if (head == null) {
        return false;
    }
    ListNode l1 = head, l2 = head.next;
    while (l1 != null && l2 != null && l2.next != null) {
        if (l1 == l2) {
            return true;
        }
        l1 = l1.next;
        l2 = l2.next.next;
    }
    return false;
}

## #


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值