16. 最接近的三数之和【中等题】
思路:【排序+双指针】
- 这题我本来只是试试暴力能不能过,结果意外的过了,也许是测试用例太少?总之过了,用时241ms击败5%。暴力就是用3层for循环遍历所有可能的三数之和,找出最接近target的。
- 然后看了题解,题解用的是排序+双指针,降低了时间复杂度,由暴力的O(n3)降到O(n2)。
- 思路跟题解一样,毕竟就是参考的题解,我的具体实现是这样的:
- 先对数组nums进行排序,设nums的长度为len,最接近的三数之和为ans(初值为0),其与target的差值最小,为min,初值为int类型的上界。
- 遍历nums中每一个数字,将其作为第一个加数,然后固定它,定义左指针left,初值为i+1(i为第一个加数的下标),定义右指针right,初值为len-1;定义三数之和sum,初值为第一个加数nums[i]。
- 进入一个while循环,退出条件为left>=right。在while循环中,sum加等左指针指向的数与右指针指向的数的和,即此时sum表示三数之和,然后判断sum与target的大小关系,如果sum>target,那么为了找出最接近的三数之和,应该把right左移1位,因为数组已经排过序了,从左到右依次递增;同理如果sum<target,那么将left右移1位;如果sum=target,那么此时sum就是最接近target的数,没有之一,此时直接返回sum即可。
- 判断过大小之后,将获得的sum与target的差的绝对值(表示sum与target之间的距离)与min相比较,如果距离比min更小,那么就将min更新为距离,并将ans更新为当前sum。
- 当所有循环结束之后,此时的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. 电话号码的字母组合【中等题】
思路:【暴力枚举】
- 定义泛型为String的列表ans用来接收要返回的答案,即所有可能的电话号码的字母组合,设电话号码长度为len,如果len是0,那么直接返回ans,此时ans还是空的。
- 定义字符串类型数组strings,依次存储2-9对应的字母组成的字符串,数字与字符串下标的对应关系为:下标=数字-2。
- 第一步已经把号码长度为0的情况排除了,那么号码长度至少为1。假设号码长度就是1,那么只需将下标为0的数字对应的字母分别添加到ans中即可。
- 如果号码长度大于1,那么从下标为1处开始往后遍历字符串类型的电话号码,此时定义一个泛型为String的列表temp作为缓存用来存储当前数字对应的字母与现在ans中已有的各种情况组合成的新组合;
- 遍历ans中的每一个组合,将ans中的所有组合都更新为:添加了当前数字对应的所有字母的新组合,并将这个新组合添加到temp中,遍历结束之后,将ans更新为temp。
- 最后返回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. 找出星型图的中心节点