16. 最接近的三数之和 / 17. 电话号码的字母组合

16. 最接近的三数之和【中等题】

思路:【排序+双指针】

  1. 这题我本来只是试试暴力能不能过,结果意外的过了,也许是测试用例太少?总之过了,用时241ms击败5%。暴力就是用3层for循环遍历所有可能的三数之和,找出最接近target的。
  2. 然后看了题解,题解用的是排序+双指针,降低了时间复杂度,由暴力的O(n3)降到O(n2)。
  3. 思路跟题解一样,毕竟就是参考的题解,我的具体实现是这样的:
  4. 先对数组nums进行排序,设nums的长度为len,最接近的三数之和为ans(初值为0),其与target的差值最小,为min,初值为int类型的上界。
  5. 遍历nums中每一个数字,将其作为第一个加数,然后固定它,定义左指针left,初值为i+1(i为第一个加数的下标),定义右指针right,初值为len-1;定义三数之和sum,初值为第一个加数nums[i]。
  6. 进入一个while循环,退出条件为left>=right。在while循环中,sum加等左指针指向的数与右指针指向的数的和,即此时sum表示三数之和,然后判断sum与target的大小关系,如果sum>target,那么为了找出最接近的三数之和,应该把right左移1位,因为数组已经排过序了,从左到右依次递增;同理如果sum<target,那么将left右移1位;如果sum=target,那么此时sum就是最接近target的数,没有之一,此时直接返回sum即可。
  7. 判断过大小之后,将获得的sum与target的差的绝对值(表示sum与target之间的距离)与min相比较,如果距离比min更小,那么就将min更新为距离,并将ans更新为当前sum。
  8. 当所有循环结束之后,此时的ans就表示的是最接近target的三数之和,返回ans即可。

代码:

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int min = Integer.MAX_VALUE,ans = 0,len = nums.length;
        for (int i = 0; i < len; i++) {
            int left = i+1,right = len-1,sum = nums[i];
            while (left<right){
                sum += nums[left]+nums[right];
                if (sum>target){
                    right--;
                }else if (sum<target){
                    left++;
                }else {
                    return sum;
                }
                if (Math.abs(sum-target)<min){
                    min = Math.abs(sum-target);
                    ans = sum;
                }
                if (left<right){
                    sum = nums[i];
                }
            }
        }
        return ans;
    }
}

用时;

与题解一样都是7ms。


17. 电话号码的字母组合【中等题】

思路:【暴力枚举】

  1. 定义泛型为String的列表ans用来接收要返回的答案,即所有可能的电话号码的字母组合,设电话号码长度为len,如果len是0,那么直接返回ans,此时ans还是空的。
  2. 定义字符串类型数组strings,依次存储2-9对应的字母组成的字符串,数字与字符串下标的对应关系为:下标=数字-2。
  3. 第一步已经把号码长度为0的情况排除了,那么号码长度至少为1。假设号码长度就是1,那么只需将下标为0的数字对应的字母分别添加到ans中即可。
  4. 如果号码长度大于1,那么从下标为1处开始往后遍历字符串类型的电话号码,此时定义一个泛型为String的列表temp作为缓存用来存储当前数字对应的字母与现在ans中已有的各种情况组合成的新组合;
  5. 遍历ans中的每一个组合,将ans中的所有组合都更新为:添加了当前数字对应的所有字母的新组合,并将这个新组合添加到temp中,遍历结束之后,将ans更新为temp。
  6. 最后返回ans。

代码:

class Solution {
    public List<String> letterCombinations(String digits) {
        List<String> ans = new ArrayList<>();
        String[] strings = {"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
        int len = digits.length();
        if (len == 0){
            return ans;
        }
        for (char ch : strings[digits.charAt(0)-'2'].toCharArray()){
            ans.add(String.valueOf(ch));
        }
        for (int i = 1; i < len; i++) {
            List<String> temp = new ArrayList<>();
            for (String cur : ans) {
                for (char need : strings[digits.charAt(i)-'2'].toCharArray()) {
                    temp.add(cur + need);
                }
            }
            ans = temp;
        }
        return ans;
    }
}

用时:

我的思路是,先把ans中添加第1位数字代表的所有字母,然后在现有ans的所有元素后边,添加第2位数字代表的所有字母;然后在现有ans的所有元素后边,添加第3位数字代表的所有字母,…依次类推就得到了所有电话号码的字母组合。
但是用时5ms,比题解的1ms慢了也太多了。


注:

今天的每日一题前几天刚写过,链接在这里。
1791. 找出星型图的中心节点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值