01.Two sum(两数之和):

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 

示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]

解题思路:

1、创建一个map

2、for循环遍历nums数组

3、用target减nums[i]

4、检查map里有没有这个数:如果有则返回结果,如果没有则把num[i]当作key,i当作value放入map中

代码:

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
    const map = new Map();
    for(let i = 0; i < nums.length; i ++) {
        const complement = target - nums[i];
        if(map.has(complement)) {
            return [map.get(complement),i]
        }else {
            map.set(nums[i],i);
        }
    }
    return [];
};

02.Add Two Numbers(两数相加):

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

2.jpg

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807

示例 2:
输入:l1 = [0], l2 = [0]
输出:[0]

示例 3:
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

解题思路:

  • 将其结果存在一个新的链表中
  • 定义一个dummy,头结点
  • 定义一个carry,用于存储某两个结点相加起来的值大于9的情况,如果大于,将个位数存入其中
  • 定义一个curr,用于一个一个遍历新链表

代码:

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var addTwoNumbers = function(l1, l2) {
    let dummy = new ListNode();//创建一个dummy头结点
    let curr = dummy;//用于一个一个遍历新链表
    let carry = 0;//用于记录是否要进位+1

    while(l1 != null || l2 != null) {
        let sum = 0;//记录和
        if(l1 != null) {
            sum += l1.val;//将结点的值加到sum中
            l1 = l1.next;//向后移动一位
        }
        if(l2 != null) {
            sum += l2.val;//将结点的值加到sum中
            l2 = l2.next;//向后移动一位
        }
        sum += carry;//加上carry的值
        curr.next = new ListNode(sum % 10);//新建一个结点,指向curr的后一位
        carry = Math.floor(sum / 10);//判断sum值是否大于等于10,如果大于,取个位,存入carry
        curr = curr.next;//curr向后移动一位
    }
    //判断,如果carry>0的,新建一个结点,
    if(carry > 0) {
        curr.next = new ListNode(carry);
    }
    //return 头结点的下一位
    return dummy.next;
};

03.无重复字符的最长字串:

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

解题思路:

  • sliding window
  • 创建一个set
  • 两个指针

    • 第一个指向字符串的开头
    • 第二个随着for循环遍历字符串
  • 如果set里没有s[i],说明目前为止还没有重复的字符,把s[i]添加到set里,然后更新最大不重复字符的数量
  • 如果set里有s[i],则从set里删除s[j],并且递增j,再检查set里是否有s[i],如此反复知道set里没有s[i]为止
  • 直到遍历完整个字符串

代码:

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
    // 创建一个set
    const set = new Set();
    // 定义两个指针,分别为i,j,maxLength为字串最大值
    let i = 0, j = 0, maxLength = 0;
    // 判断,如果字符串s为0,子串也为0
    if(s.length == 0) {
        return 0;
    }
    // i,j从第一个元素开始遍历
    for(i; i < s.length; i ++) {
        // 如果set中不存在s[i]这个值,将其添加
        if(!set.has(s[i])) {
            set.add(s[i]);
            maxLength = Math.max(maxLength,set.size);
        }else {
            while(set.has(s[i])) {
                // 删除s[j]的值,并将j向后移动
                set.delete(s[j]);
                j ++;
            }
            set.add(s[i]);
        }
    }
    return maxLength;
};

05.最长回文字串:

解题思路:

  • 如果字符串长度小于2,直接返回原字符串
  • 定义两个变量,一个start存储当前找到的最大回文字符串的起始位置,另一个maxLength记录字符串的长度(终止位置就是start+maxLength)
  • 创建一个helper function,判断左边和右边是否越界,同时最左边的字符是否等于右边的字符,如果以上3个条件都满足,则判断是否需要更新回文字符串最大长度即最大字符串的起始位置,然后将left--,right++,继续判断,直到不满足三个条件之一
  • 遍历字符串,每个位置调用helper function两遍,第一遍检查i-1,i+1,第二遍检查i,i+1

代码:

/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function(s) {
    if(s.length < 2) {
        return s;
    }

    let start = 0;
    let maxLength = 1;

    function expandAroundCenter(left,right) {
        while(left >= 0 && right < s.length && s[left] === s[right]) {
            if(right - left + 1 > maxLength) {
                maxLength = right - left + 1;
                start = left;
            }
            left --;
            right ++;
        }
    }
     for(let i = 0; i < s.length; i ++) {
         expandAroundCenter(i - 1, i + 1);
        expandAroundCenter(i, i + 1);
    }
    return s.substring(start,start + maxLength)
};

15.三数之和:

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

示例 2:
输入:nums = []
输出:[]

示例 3:
输入:nums = [0]
输出:[]
    

解题思路:

  • 给数组排序
  • 遍历数组,从0遍历到length-2
  • 如果当前的数字等于前一个数字,则跳过这个数
  • 如果数字不同,则设置start = i + 1,end = length - 1,查看i,start和end三个数的和比零大还是小,如果比0小,start++,如果比0大,end--,如果等于0,把这三个数加入到结果里
  • 返回结果

代码:

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    const result = [];
    nums.sort(function(a,b) {
        return a - b;
    })
    
    for(let i = 0; i < nums.length - 2; i ++) {
        if(i === 0 || nums[i] !== nums[i - 1]) {
            let start = i + 1,end = nums.length - 1;
            while(start < end) {
                if(nums[i] + nums[start] + nums[end] === 0) {
                    result.push([nums[i],nums[start],nums[end]])
                    start ++;
                    end --;
                    while(start < end && nums[start] === nums[start - 1]) {
                        start ++;
                    }
                    while(start < end && nums[end] === nums[end + 1]) {
                        end --;
                    }
                }else if(nums[i] + nums[start] + nums[end] < 0) {
                    start ++;
                }else if(nums[i] + nums[start] + nums[end] > 0){
                    end --;
                }
            }
        }
    }
    return result;
};

21.合并两个有序链表:

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例 1:

21.png

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

解体思路:

本题可以使用递归来解,将两个链表头部较小的一个与剩下的元素合并,并返回排好序的链表头,当两条链表中的一条为空时终止递归。

代码:

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} list1
 * @param {ListNode} list2
 * @return {ListNode}
 */
var mergeTwoLists = function(list1, list2) {
    if (list1 === null) {
        return list2
    }
    if(list2 === null) {
        return list1
    }
    if(list1.val < list2.val) {
        list1.next = mergeTwoLists(list1.next,list2)
        return list1;
    }else {
        list2.next = mergeTwoLists(list1,list2.next)
        return list2
    }
};

26.删除有序数组中的重复项:

给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。
将最终结果插入 nums 的前 k 个位置后返回 k 。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
判题标准:
系统会用下面的代码来测试你的题解:
int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案
int k = removeDuplicates(nums); // 调用
assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
    assert nums[i] == expectedNums[i];
}
如果所有断言都通过,那么您的题解将被 通过。

解题思路:

使用快慢指针来记录遍历的坐标。
开始时这两个指针都指向第一个数字
如果两个指针指的数字相同,则快指针向前走一步
如果不同,则两个指针都向前走一步
当快指针走完整个数组后,慢指针当前的坐标加 1 就是数组中不同数字的个数

代码:

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    const size = nums.length;
    if (size == 0) return 0;
    let slowP = 0;  //定义一个慢指针下标初始值0
    for(let fastP = 1; fastP < size; fastP ++) {    //遍历的时候,快指针从下标1开始
        if(nums[fastP] !== nums[slowP]) {   //如果快指针的值不等于慢指针的值。将慢指针向后移动,并且将快指针的值赋给慢指针
            slowP ++;
            nums[slowP] = nums[fastP];//将快指针的值赋给慢指针指向的位置
        }
    }
    return slowP + 1
};

66.加一:

给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。

示例 1:
输入:digits = [1,2,3]
输出:[1,2,4]
解释:输入数组表示数字 123。

示例 2:
输入:digits = [4,3,2,1]
输出:[4,3,2,2]
解释:输入数组表示数字 4321。

示例 3:
输入:digits = [0]
输出:[1]

解题思路:

这道题其实我们可以把它想象成小学生练习加法,只不过现在是固定的“加一”那么我们只需要考虑如何通过遍历来实现这个加法的过程就好了。

加法我们知道要从低位到高位进行运算,那么只需要对数组进行一次反向遍历即可。

伪代码:

for(int i = n - 1; i > - 1; i --) {
  内部逻辑
}

内部逻辑的话,其实有三种情况:

第一种情况是最简单的,我们只需将数组的最后一位进行+1 操作就好了

第二种情况稍微多了一个步骤:我们需要把个位的 carry 向前进一位并在计算是否有更多的进位

第三种其实和第二种是一样的操作,只是由于我们知道数组的长度是固定的,所以当我们遇到情况三的时候需要扩大数组的长度。我们只需要在结果数组前多加上一位就好了。

代码:

/**
 * @param {number[]} digits
 * @return {number[]}
 */
var plusOne = function(digits) {
    let carry = 1;  //初始化一个carry = 1
    // 对数组进行反向遍历
    for(let i = digits.length-1; i > -1; i --) {
        if(carry) {
            let sum = carry + digits[i];
            digits[i] = sum % 10;
            carry = sum > 9 ? 1 : 0;
        }
    }
    if(carry === 1) {
        digits.unshift(1)
    }
    return digits;
};

88.合并两个有序数组:

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

示例 2:
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。

示例 3:
输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

解题思路:

我们能只要从后往前比较,并从后往前插入即可
我们需要三个指针:
写指针 current, 用于记录当前填补到那个位置了
m 用于记录 nums1 数组处理到哪个元素了
n 用于记录 nums2 数组处理到哪个元素了

代码:

/**
 * @param {number[]} nums1
 * @param {number} m
 * @param {number[]} nums2
 * @param {number} n
 * @return {void} Do not return anything, modify nums1 in-place instead.
 */
var merge = function(nums1, m, nums2, n) {
    let current = m + n -1  //定义一个指针,指向nums1的末尾
    while(current >= 0) {
        if(n === 0) return  //如果n的长度为0,没必要继续
        if(nums1[m - 1] > nums2[n - 1]) {
            nums1[current --] = nums1[--m]
        }else{
            nums1[current--] = nums2[--n]
        }
        if(m < 1) {
            nums1[current--] = nums2[--n]
            continue
        }
        if(n < 1) {
            nums1[current--] = nums1[--m]
            continue
        }
    }
};
最后修改:2024 年 04 月 21 日 05 : 33 PM
如果觉得我的文章对你有用,请随意赞赏