最后一个单词的长度 && 三数之和 && 两数之和
# 最后一个单词的长度
这是力扣第 58 题
给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。
# 解题思路
这是一道简单题,题意清晰,比较容易理解,根据字符串返回最后一个单词的长度。看到这题第一眼,很显然能想到遍历字符串来实现。又因为这是字符串里包含单词且单词也是字符串,所以也可以考虑将字符串转换为数组。因此接下来会分别介绍一下这两种解题思路。
# 遍历法
这题用遍历法就很简单了。因为题目是让我们求出最后一个单词的长度,因此可以考虑反向遍历。反向遍历是怎么样的呢?我们可以从最后一个字母开始遍历字符串,由于每个单词之间都是存在空格的,所以当第一次遇到空格时,说明此时遍历到的每个字母都属于最后一个单词,因此遍历到的字母数量即为最后一个单词的长度。最后通过 length
返回最终结果就行了。
相关代码如下:
var lengthOfLastWord = function(s) {
var len=0
for(var i=s.length-1;i>=0;i--){
var char=s[i]
if(char!==" "){
len++
}else{
if(len>0) break
}
}
return len
};
# 转换数组法
除了使用遍历法,还可以通过将字符串转换为数组来解决此题。将字符串转换为数组,通过 filter()
过滤空格,最后返回最终结果即可。过程以及代码十分简单。但是相比较于这种方式,我更推荐上面的遍历法,毕竟这种方式对于这题而言还是会有点不好完全理解。
相关代码如下:
var lengthOfLastWord = function (s) {
let str = s.split(' ');
str = str.filter((item) => !item);
return str[str.length - 1].length;
};
# 三数之和
这是力扣第 15 题
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请 你返回所有和为 0 且不重复的三元组。 注意:答案中不可以包含重复的三元组。
# 解题思路
这道题是一道中等难度题,在原先两数之和的基础上又加入了一个数变成三数之和,因此可以从两数之和上来突破。最容易想到的思路是,两数之和通过暴力解法即通过两层 for
循环遍历数组,那么,在两层 for
循环的基础上再加入一层循环即可。
# 暴力解法
暴力解法不用多说,只需三层 for
循环即可。暴力解法的本质就是 for
循环,通过层层循环来到达预期结果,不过在时间复杂度上会差强人意,不如其他的方法。
相关代码如下:
var threeSum = function(nums) {
for(let i=0;i<nums.length;i++){
let currt = nums[i];
for(let j=i+1;j<nums.length;j++){
for(let l=j+1;j<nums.length;l++){
let sum=nums[j]+nums[l];
}
}
if(currt+sum===0){
return [nums[i],nums[j],nums[l]]
}else{
return false;
}
}
};
# 双指针法
在两数之和中,可以使用双指针法来解决,那么,对于三数之和,是否也可以使用同种方法呢?当然是可以的。之前就有提到过,双指针法比较重要,掌握好双指针能解决很多题目。
对数组进行排序,排序后固定一个数 nums[i]
,再使用左右指针指向 nums[i]
后面的两端,数字分别为 nums[L]
和 nums[R]
,计算三个数的和 sum
判断是否满足为 0。
相关代码如下:
var threeSum = function(nums) {
let ans = [];
const len = nums.length;
if(nums == null || len < 3) return ans;
nums.sort((a, b) => a - b); // 排序
for (let i = 0; i < len ; i++) {
if(nums[i] > 0) break;
if(i > 0 && nums[i] == nums[i-1]) continue;
let L = i+1;
let R = len-1;
while(L < R){
const sum = nums[i] + nums[L] + nums[R];
if(sum == 0){
ans.push([nums[i],nums[L],nums[R]]);
while (L<R && nums[L] == nums[L+1]) L++;
while (L<R && nums[R] == nums[R-1]) R--;
L++;
R--;
}
else if (sum < 0) L++;
else if (sum > 0) R--;
}
}
return ans;
};
这就是双指针法,相比较暴力法可能理解起来会有些难度,但是从时间复杂度上来说会降低很多,所以可以多分析分析这题,对理解双指针法有很大好处。
# 两数之和
这是力扣第 1 题
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。 你可以按任意顺序返回答案。
# 解题思路
两数之和,第一题力扣,这是多少人第一次刷题的回忆,我相信 90% 的人的第一次刷题记忆是从这道题开始的。毫无例外,我也是从这题开始的,因此这题也是十分经典(毕竟是我们梦开始的地方 😎)。题目有非常多的解法,最简单直接的无疑是暴力解法。接下来就来介绍一下以下几种方法。
# 暴力解法
暴力解法十分简单,只需通过两层循环遍历数组找到 target
即可。这道题用暴力解法是特别容易理解的(遇题不会就暴力 😎)。整体解题思路如下:
- 两次
for
循环,第一次for
循环遍历取当前元素值,第二次for
循环遍历取下一元素的值, - 然后判断两个元素的和是否等于目标结果,并记录结果索引到数组。
相关代码如下:
var twoSum = function(nums, target) {
for(let i = 0, len = nums.length;i < len;i++){
for(let j = i + 1;j < len;j++) {
if(nums[i] + nums[j] === target) {
return [i, j];
}
}
}
return [-1, -1];
};
# 其他解法
这道题有很多其他解法,大家可以去多看看。这里我就附上一种其他思路的代码,具体思路和暴力解法大差不差,大家可以多多研究一下,理清楚其中的奥妙。
相关代码如下:
var twoSum = function(nums, target) {
var indexarr =[];
for(var i =0; i<nums.length; i++){
var targetIndex = nums.indexOf(target- nums[i]);
if(targetIndex!=-1&&targetIndex!==i){
indexarr=[i,targetIndex]
break;
}
}
return indexarr
};