「刷leetcode题」数组

1 两个数之和(2020.09.12)

在这里插入图片描述
1 自己解法:
思路:主要是双循环来一个一个试.

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
    let res = []
    for(let i = 0; i<nums.length; i++){
        for(let j = i+1 ; j<nums.length; j++){
            if(nums[i] + nums[j] === target){
                res.push(i, j)
                return res
            }
        }
    }
};

2 优秀解法
注:此题使用ES6的Map,使得时间复杂度降为O(n)
关于Map和Set的使用要重点掌握!!!

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

2 删除排序数组中的重复项(27,2020.09.15)

在这里插入图片描述
1 自己的解法:
双循环来判断去重

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    for(let i = 0; i<nums.length; i++){
        let temp_len = nums.length
        let j = i + 1
        while(j<nums.length){
            if(nums[i] === nums[j]){
                nums.splice(j, 1)
                j = i + 1
            }else{
                j++
            }
        }
    }
};

2 优秀解法1
利用两个变量来比较

var removeDuplicates = function(nums) {
    let cur = nums[0]
    let i = 1
    while(i < nums.length){
        if(nums[i] === cur){
            nums.splice(i, 1)
        }else{
            cur = nums[i++]
        }
    }
    return nums.length
};

3 优秀解法2
双指针, 思路地址

var removeDuplicates = function(nums) {
    let slow = 0
    let fast = 1
    while(fast<nums.length){
        if(nums[slow] === nums[fast]){
            fast++
        }else{
            nums[++slow] = nums[fast]
        }
    }
    nums.splice(slow+1)
    return nums.length
}

3 移除元素(27,2020.09.18)

在这里插入图片描述
1 自己的解法:
逐个比对删除

/**
 * @param {number[]} nums
 * @param {number} val
 * @return {number}
 */
var removeElement = function(nums, val) {
   let i = 0
    while(i<nums.length){
        if(nums[i] === val){
            nums.splice(i, 1)
        }else{
            i++
        }
    }
    return nums.length
};

2 优秀解法1
双指针:
在这里插入图片描述

var removeElement = function(nums, val){
    let i = 0 
    for(let j=0; j<nums.length; j++){
        if(nums[j] !== val){
            nums[i] = nums[j]
            i++
        }
    }
    return i
}

3 优秀解法2
双指针优化-当删除元素很少时
在这里插入图片描述

var removeElement = function(nums, val){
    let i = 0
    let len = nums.length
    while(i<len){
        if(nums[i] === val){
            nums[i] = nums[len-1]
            len--
        }else{
            i++
        }
    }
    return len
}

4 搜索插入位置(35, 2020.09.21)

在这里插入图片描述
1 自己的解法:
思路:

  • 先考虑相等情况然后返回index
  • 然后考虑不相等情况(除了tar比数字任何数都大的情况), 当target小于当前的数组的值时, 返回对应的index即可.
  • 最后tar比数字任何数都大的情况, 直接返回数组长度
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var searchInsert = function(nums, target) {
    for(let i=0; i<=nums.length; i++){
        if(nums[i] === target && i<nums.length){
            return i
        }else if(nums[i]>target && i<nums.length){
            return i 
        }else if(i === nums.length){
            return nums.length
        }    
    }
};

自己的解法-优化

  • 首先tar比数字任何数都大的情况, 直接返回数组长度
  • 然后当target小于等于当前的数组的值时, 返回对应的index即可.
var searchInsert = function(nums, target) {
    let len = nums.length
    if(target > nums[len-1] )
        return len
    for(let i=0; i<len; i++){
        if(target <= nums[i]){
            return i
        }
    }
};

2 优秀的解法1:
二分查找:
mid=(left+right)>>1的含义
右移运算符>>,运算结果正好能对应一个整数的二分之一值,这就正好能代替数学上的除2运算,但是比除2运算要快。
mid=((left+right)>>1)(建议用括号包裹)相当于mid=(left+right)/2

var searchInsert = function(nums, target) {
    let left = 0
    let right = nums.length -1
    while(left <= right){
        let mid = ((right - left) >> 1) + left
        if(target > nums[mid]){
            left  = mid + 1
        }else{
            right = mid - 1
        } 
    }
    return left
};

5 最大子序和(53, 2020.09.23)

在这里插入图片描述

1 自己的解法:
没得思路只有暴力求解

var maxSubArray = function(nums) {
    let len = nums.length
    let max = -2147483647
    for(let i=0; i<len; i++){
        let sum = 0
        for(let j=i; j<len; j++){
            sum  = sum + nums[j]
            if(sum > max){
                max = sum
            }
        }
    }
    return max
};

2 优秀的解法
思路: 满足上一个大于0就累加到当前数组位置

var maxSubArray = function(nums) {
    for(let i=1; i<nums.length; i++){
        if(nums[i -1] > 0){
            nums[i] += nums[i-1]
        }
    }
    return Math.max(...nums)
};

6 加一(66, 2020.09.29)

1 优秀的解法一:
思路: 利用可能超过max_save_integer, 因此用BigInt

var plusOne = function(digits) {
    let num = BigInt(digits.join(''))
    let str = String(num + 1n)
    digits = [...str]
    digits.map(Number)
    return digits
};

2 优秀的解法二:
思路:
末位无进位,则末位加一即可,因为末位无进位,前面也不可能产生进位,比如 45 => 46

末位有进位,在中间位置进位停止,则需要找到进位的典型标志,即为当前位 %10后为 0,则前一位加 1,直到不为 0 为止,比如 499 => 500

末位有进位,并且一直进位到最前方导致结果多出一位,对于这种情况,需要在第 2 种情况遍历结束的基础上,进行单独处理,比如 999 => 1000

var plusOne = function(digits) {
    const len = digits.length
    for(let i = len-1; i>=0; i--) {
        digits[i]++
        digits[i] %= 10;
        if(digits[i] !== 0)
            return digits
    }
    digits = [...Array(len + 1)].map(_ => 0)
    digits[0] = 1
    return digits
};

7 合并两个有序数组(88, 2020.10.01)

在这里插入图片描述

1 自己解法:
思路:直接将nums2填充到0的部分然后sort

var merge = function(nums1, m, nums2, n) {
    nums1.splice(m)
    nums1.push(...nums2)
    nums1.sort((a,b) => a-b)
};

2 优秀解法一:
思路:
在这里插入图片描述

var merge = function(nums1, m, nums2, n) {
    nums1_copy = nums1.slice(0, m)
    nums1.splice(0, m+n)
    p1 = 0
    p2 = 0
    while(p1 < m && p2 < n){
        if(nums1_copy[p1] < nums2[p2]){
            nums1.push(nums1_copy[p1++])
        }else{
            nums1.push(nums2[p2++])
        }
    }

    while(p1 < m){
        nums1.push(nums1_copy[p1++])
    }

    while(p2 < n){
        nums1.push(nums2[p2++])
    }
};

3 优秀解法二
思路:
在这里插入图片描述

var merge = function(nums1, m, nums2, n) {
    p1 = m -1
    p2 = n -1
    p = m + n -1
    while(p1 >= 0 && p2 >= 0){
        if(nums1[p1] < nums2[p2]){
            nums1[p] = nums2[p2--]
        }else{
            nums1[p] = nums1[p1--]
        }
        p--
    }
    nums1.splice(0, p2+1, ...nums2.splice(0, p2+1))

};

8 杨辉三角(Pascal’s triangle)(118, 2020.10.05)

在这里插入图片描述
1 自己的解法:
思路:

  • 首先考虑边界条件:

numRows等于1和2的情况,都为1

  • 然后开始对numRows大于2的情况:

考虑第一个和最后一个边界情况都为1

普通情况:比如,第2行第1个(2,1)的值为第1行的第0个(1,0)和第一个的和(1,1)

var generate = function(numRows) {
    let triangle = []
    for(let i=0; i<numRows; i++){
		let row = []
        if(i === 0){
            triangle.push([1])
        }else if(i === 1){
            triangle.push([1, 1])
        }else{
            for(let j=0; j<=i; j++){
                if(j === 0){
                    row.push(1)
                }else if(j === i){
                    row.push(1)
                }else{
                    row.push(triangle[i-1][j-1] + triangle[i-1][j])
                }
            }
            triangle.push(row)
        }
    }
    return triangle
};

2 优秀的解法
思路:思路和我差不多,处理row的时候是先声明了i+1长度的数组之后进行操作

var generate = function(numRows) {
    let triangle = []
    for(let i=0; i<numRows; i++){
        let row = [...Array(i + 1)].map(_ => undefined)
        row[0] = 1
        row[i] = 1
        for(let j=1; j<i; j++){
            row[j] = triangle[i-1][j-1] + triangle[i-1][j]
        }
        triangle.push(row)
    }
    return triangle
};

9 杨辉三角 II(Pascal’s triangle)(119, 2020.10.07)

在这里插入图片描述
1 自己的解法结合参考的解法:
思路:
跟 杨辉三角 别人的解法类似,只是记录上一次的记录,而不是全部的。

/**
 * @param {number} rowIndex
 * @return {number[]}
 */
var getRow = function(rowIndex) {
    let row, last
    for(let i=0; i<=rowIndex; i++){
        last = row
        row = []
        row[0] = 1
        row[i] = 1
        for(let j=1; j<i; j++){
            row[j] = last[j-1] + last[j]
        }
    }
    return row
};

10 买卖股票的最佳时机(121,2020.10.10)

在这里插入图片描述
1 自己的解法
思路:

  1. 假设第一个价格为买入价格,先处理掉示例2的条件。
  2. 然后记录每次可以卖出的最大值即可。
/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
    let max = 0
    let buy = prices[0]
    let sell = 0
    let i = 1
    while(i<prices.length){
        if(buy >= prices[i]){
            buy = prices[i++]
            continue
        }else{
            sell = prices[i]
            if(max < sell - buy){
                max = sell - buy
            }
            i++
        }
    }
    return max
};

2 优秀的解法
思路:和我的差不多

/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
    let maxProfit = 0
    let buy = prices[0]
    let sell = 0
    for(let i=0; i<prices.length; i++){
        buy = Math.min(prices[i], buy)
        sell = prices[i]
        maxProfit = Math.max(maxProfit, sell - buy)
    }
    return maxProfit
};

做好初始定义

11 移动零(283,2020.10.12)

在这里插入图片描述
1 优秀的解法一
思路:
第一次遍历的时候,j指针记录非0的个数,只要是非0的统统都赋给nums[j]
第二次遍历把末尾的元素都赋为0即可

var moveZeroes = function(nums) {
    let j = 0
    for(let i=0; i<nums.length; i++){
        if(nums[i] !== 0){
            nums[j++] = nums[i]
        }
    }
    for(let i=j; i<nums.length; i++){
        nums[i] = 0
    }
};

2 优秀的解法二
思路:
这里参考了快速排序的思想,快速排序首先要确定一个待分割的元素做中间点x,然后把所有小于等于x的元素放到x的左边,大于x的元素放到其右边。
这里我们可以用0当做这个中间点,把不等于0(注意题目没说不能有负数)的放到中间点的左边,等于0的放到其右边。

var moveZeroes = function(nums) {
    let j = 0
    for(let i=0; i<nums.length; i++){
        if(nums[i] !== 0){
            let temp = nums[i]
            nums[i] = nums[j]
            nums[j++] = temp
        }
    }
};

3 优秀的解法三
思路:
其实优化的地方就是#1处(相比较解法二)。它避免了数组开头是非零元素的交换也就是阻止(i==j)时交换。

i > j 时,只需要把i的值赋值给j并把原位置的值置0。同时这里也把交换操作换成了赋值操作,减少了一条操作语句,理论上能更节省时间。

var moveZeroes = function(nums) {
    let j = 0
    for(let i=0; i<nums.length; i++){
        if(nums[i] !== 0){
            if(i > j){ // #1
                nums[j] = nums[i]
                nums[i] = 0
            }
            j++
        }
    }
};

3 移除元素(27,2020.10.14)

2 删除排序数组中的重复项(26,2020.10.14)

12 删除排序数组中的重复项 II(80,2020.10.14)

在这里插入图片描述
1 自己的解法:
思路:通过count计数,然后通过splice函数特性来写。

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    let count = 1
    let i = 1 
    while(i<nums.length){
        if(nums[i] === nums[i-1]){
            count++
            if(count > 2){
                nums.splice(i, 1)
                i--
            }
        }else{
            count = 1
        }
        i++
    }
    return nums.length
};

2 优秀的解法
思路:不使用splice来切割,用后面的来覆盖。

var removeDuplicates = function(nums) {
    let count, j = 1
	for(let i=1; i<nums.length; i++){
		if(nums[i] === nums[i-1]){
			count++
			if(count <= 2){
				nums[j++] = nums[i]
		}else{
			count = 1
		}
};

运用基础算法思想

13 颜色分类(75,2020.11.01)

在这里插入图片描述
1 自己的解法
思路:库函数排序和手写计数排序都可以完成这道问题。这里直接用JS提供的sort函数

/**
 * @param {number[]} nums
 * @return {void} Do not return anything, modify nums in-place instead.
 */
var sortColors = function(nums) {
    nums.sort()
};

2 优秀的解法
思路:
循环不变量:声明的变量在遍历的过程中需要保持定义不变。设计循环不变量的原则是 不重不漏
设计的循环不变量定义如下:
所有在子区间 [0, zero) 的元素都等于 0;
所有在子区间 [zero, i) 的元素都等于 1;
所有在子区间 [two, len - 1] 的元素都等于 2。
我的理解应该zero和two是循环不变量

var sortColors = function(nums) {
    nums.sort()
    len = nums.length
    lt = -1
    rt = len - 1

    i = 0
    while(i < rt){
        if(nums[i] === 0){
            lt++ 
            swap(nums, i, lt)
            i++
        }else if(nums[i] === 1){
            i++
        }else{
            swap(nums, i, rt)
            rt--
        }
    } 
};

function swap(nums, index1, index2){
    let temp = nums[index1]
    nums[index1] = nums[index2]
    nums[index2] = temp
}

变量的值发生变化是一个很重要的逻辑,应该单独成为一行,否则不利于调试和以后定位问题

14 数组中的第K个最大元素(215,2020.11.06)

1 自己的解法
思路:通过 sort 函数排序后,直接返回 k-1 的值

var findKthLargest = function(nums, k) {
    nums.sort((a, b) => b - a)
    return nums[k-1]
};

2 优秀的解法
思路:利用快排的思路,对拆分(partition)部分进行操作

var findKthLargest = function(nums, k) {
    len = nums.length
    left = 0
    right = len - 1
    target = len - k
    while(true){
        let index = partition(nums, left, right)
        if(index === target){
            return nums[index]
        }else if(index < target){
            left = index + 1
        }else{
            right = index - 1
        }
    }
};

// 循环不变量:[left + 1, j] < pivot
// (j, i) >= pivot
var partition = function(nums, left, right){
    pivot = nums[left]
    j = left
    for(let i=left+1; i<right+1; i++){
        if(nums[i] < pivot){
            j++
            [nums[i], nums[j]] = [nums[j], nums[i]]
        }
    }
    [nums[left], nums[j]] = [nums[j], nums[left]]
    return j
}

7 合并两个有序数组(88, 2020.10.01)

双索引技巧 - 对撞指针

15 两数之和 II - 输入有序数组(167,2020.11.11)

在这里插入图片描述
1 优秀的解法:
思路:用双指针来完成

var twoSum = function(numbers, target) {
    let i = 0
    let j = numbers.length - 1
    while(i < j){
        const sum = numbers[i] + numbers[j]
        if(target > sum){
            i += 1
        }else if(target < sum){
            j -= 1
        }else{
            return [i+1, j+1]
        }
    }
};

16 验证回文串(125,2020.11.14)

在这里插入图片描述
1 自己的解法:
思路:双指针

var isPalindrome = function(s) {
    let i = 0;
    let j = s.length - 1;
    const regExp = /([a-zA-Z0-9])/;
    while(i < j){
        if(regExp.test(s[i]) && regExp.test(s[j])){
            if(s[i].toLowerCase() === s[j].toLowerCase() ){
                i += 1;
                j -= 1;
            }else{
                return false;
            }
        }else if(!regExp.test(s[i])){
            i += 1;
        }else if(!regExp.test(s[j])) {
            j -= 1;
        }
    }
    return  true
};

2 别人的解法:
思路:先过滤字符串然后通过反转或者双指正来验证是否为回文串

var isPalindrome = function(s) {
    const regExp = /([\W|_])/g;
    s = s.replace(regExp, '').toLowerCase();
    return  s === s.split('').reverse().join('');
};

17 反转字符串中的元音字母(345,2020.11.16)

在这里插入图片描述
1 自己的解法
思路:利用双指针

var reverseVowels = function(s) {
    s = s.split('')
    let i = 0
    let j = s.length - 1
    let vowel = 'aeiouAEIOU'
    while(i < j){
        if(vowel.indexOf(s[i]) !== -1 && vowel.indexOf(s[j]) !== -1) {
            const temp = s[i]
            s[i] = s[j]
            s[j] = temp
            i += 1
            j -= 1
        }
        if(vowel.indexOf(s[i]) === -1){
            i += 1
        }
        if(vowel.indexOf(s[j]) === -1){
            j -= 1
        }
    }

    return s.join('')
};

18 盛最多水的容器 (11,2020.11.18)

在这里插入图片描述
1 自己的解法:
思路:利用双指针

var maxArea = function(height) {
    let i = 0;
    let j = height.length - 1;
    areaMax = 0
    while(i<j){
        h = height[i] < height[j] ? height[i] : height[j];
        w = j - i;
        area = h * w;
        if(area >  areaMax){
            areaMax = area;
        }

        if(height[i] < height[j]){
            i += 1;
        }else{
            j -= 1;
        }
    }
    return areaMax;
};

2 针对1代码优化:

var maxArea = function(height) {
    let i = 0;
    let j = height.length - 1;
    areaMax = 0
    while(i<j){
        if(height[i] < height[j]){
            areaMax = Math.max(areaMax, height[i] * (j - i))
            i += 1
        }else{
            areaMax = Math.max(areaMax, height[j] * (j - i))
            j -= 1
        }
    }
    return areaMax;
};

19 长度最小的子数组(209,2020.11.21)

在这里插入图片描述
1 优秀的解法
思路:先左扩张找到满足 sum >= s 的条件的可行解, 然后右收缩优化可行解(最小长度)

var minSubArrayLen = function(s, nums) {
    let minLenth = Infinity
    let i = 0
    let j = 0
    let sum = 0
    while(j< nums.length){
        sum += nums[j]
        while(sum >= s){
            minLenth = Math.min(minLenth, j - i + 1)
            sum -= nums[i]
            i += 1
        }
        j += 1
    }
    return minLenth === Infinity ? 0 : minLenth
};

20 三数之和(15,2021.02.01)

在这里插入图片描述
1 优秀的解法:
思路:先对数组进行排序,然后通过双指针方法来寻找: 固定 3 个指针中最左(最小)数字的指针 k,双指针 i,j 分设在数组索引(k,len(nums)两端,通过双指针交替向中间移动,记录对于每个固定指针 k 的所有满足,nums[k] + nums[i] + nums[j] == 0的i,j组合。

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    nums.sort((a,b)=> a-b)
    let res = []
    for(let k=0; k<nums.length - 2; k++){
        if(nums[k] > 0) break
        if(k > 0 && nums[k-1] === nums[k]) continue
        let i = k + 1
        let j = nums.length - 1
        while(i < j){
            let sum = nums[k] + nums[i] + nums[j]
            if(sum < 0){
                i += 1
                while(i < j && nums[i] === nums[i - 1]){
                    i += 1
                }
            }else if(sum > 0){
                j -= 1
                while(i < j && nums[j] === nums[j + 1]){
                    j -= 1
                }
            }else{
                res.push([nums[k], nums[i], nums[j]])
                i += 1
                j -= 1
                while(i < j && nums[i] === nums[i - 1]){
                    i += 1
                }
                while(i < j && nums[j] === nums[j + 1]){
                    j -= 1
                }
            }
        }
    }
    return res
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值