最后一个单词的长度 && 三数之和 && 两数之和

2023/1/2 LeetCode

# 最后一个单词的长度

这是力扣第 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
};
강남역 4번 출구
Plastic / Fallin` Dild