每周算法1

记录一下做算法的历程,之后的算法小编会用javaScript来进行编写,有和我一样是前端的小伙伴同时也想提高自己的算法能力的可以一起学习。

第一周我想尝试一些双指针类型的题目。

在这周的算法学习中,js数组的删除方法用到的比较多。

  • splice(index,len,[item]) 可以用来替换/删除/添加数组内某一个或者几个值。
    • 替换:替换起始下标为index,长度为len的一个值item
    var arr = ['a','b','c','d']
    arr.splice(1,2,'item')   // ['a','item','d']
    
    • 删除:删除起始下标为index,长度为len的一个值
    var arr = ['a','b','c','d']
    arr.splice(1,2) // ['a','d']
    
    • 添加:len设置为0,item为添加的值
    var arr = ['a','b','c','d']
    arr.splice(1,0,'item') // ['a','item','b','c','d']
    
  1. 三数之和(排序加双指针)
/**
 * @param {number[]} nums
 * @return {number[][]}
 */
function compare(a,b) {
  return a-b;
}
var threeSum = function(nums) {
  let res=[]
  let len=nums.length
  if(nums == null || len < 3) return res;
  //先对数组进行排序
  nums.sort(compare)  
  for(let i=0;i<len;i++){
    // 如果大于0则之后相加不可能等于0
    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){
      let sum=nums[i]+nums[L]+nums[R]
      if(sum==0){
        res.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 res
};

console.log(threeSum([-1, 0, 1, 2, -1, -4]))
console.log(threeSum([-1, 0, 1, 2, -1, 2]))
console.log(threeSum([0,0,0,0]))
console.log(threeSum([1,1,-2]))
console.log(threeSum([1,1,0]))
console.log(threeSum([0,0,0]))
console.log(threeSum([-2,0,1,1,2]))

2.删除排序数组中的重复项

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

3.删除排序数组中的重复项 II

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

4.移动零

/**
 * @param {number[]} nums
 * @return {void} Do not return anything, modify nums in-place instead.
 */
var moveZeroes = function(nums) {
  let L=0
  let R=1
  //这里必须为nums.length-1,否则会陷入死循环,因为num[nums.length+1]!=0是undefined
  while(R<=nums.length-1){
    //如果第L个是非零数字,则两个指针同时向前
    if(nums[L]!=0){
      L++
      R++
    }
    else if(R<=nums.length&&nums[L]==0 && nums[R]!=0){
      nums[L]=nums[R]
      nums[R]=0
      L++
      R++
    }
    else if(nums[L]==0 && nums[R]==0){
      while(R<=nums.length-1 && nums[R]==0){
        R++;
      }
    }
  }
  return nums
};

5.最接近的三数之和

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var threeSumClosest = function(nums, target) {
  let len=nums.length
  let res=[]
  let index=0
  if(len<3) return res[0]
  if(len==3) return nums[0]+nums[1]+nums[2]
  for(let i=0;i<len;i++){
    let L=i+1
    let R=L+1
    while(L<len){
      while(R<len){
        res[index]=nums[i]+nums[L]+nums[R]
        R++
        index++
      }
      L++
      R=L+1
    }
  }
  let resNum=[]
  for(let i=0;i<index;i++){
    // console.log(index,res[i])
    resNum[i]=Math.abs(res[i]-target)
    // console.log(resNum[i])
  }
  let min = resNum[0]
  let resMin=res[0]
  for(let i=0;i<index;i++){
    if(min>resNum[i]){
      min=resNum[i]
      resMin=res[i]
    }
  }
  return resMin;
};
  • 上面的这个代码时间复杂度太高,优化代码为以下:
    • 与上面第一题的思路一样都是:
    • 现将数组从小到大排序,从左到右先固定一个数,头尾双指针进行扫描
    • 如果sum大于target,就左移右指针,否则右移左指针
    • 在看sum-target的绝对值是否比之前的更小了,如果是,更新
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var threeSumClosest = function(nums, target) {
  //排序
  let numsSort = nums.sort((a,b)=>{return a-b})
  let len=nums.length
  if(len==3) return nums[0]+nums[1]+nums[2]
  let sum
  let cha=1000
  let res
  for(let i=0;i<len;i++){
    let L=i+1
    let R=len-1
    while(L<R){
      sum=numsSort[i]+numsSort[L]+numsSort[R]
      if(Math.abs(sum-target)<cha){
        res=sum
        cha=Math.abs(sum-target)
      }
      if(sum<target){
        L++
      }
      if(sum>target){
        R--
      }
      if(cha==0){
        return sum
      }
    }
  }
  return res
};

6.子集

  • 循环nums,每次添加一个nums[i],每添加一个nums[i],就与res数组中前面的所有元素组成一个新的数组(例如,添加[1],[2],当添加元素[2]时,循环res数组,将元素[2]与res数组前面的元素组合)
/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var subsets = function(nums) {
  let res = []
  let arr1=[]
  let num=0
  for(let i=0;i<nums.length;i++){
    arr1=[nums[i]]
    res.push(arr1)
    num=0
    let len=res.length
    for(let j=0;j<res.length;j++){
      if(!res[j].includes(nums[i])){
        let arr=[].concat(res[j])
        arr.push(nums[i])
        res.push(arr)
        num++
      }
      if(num-1==len){
        break;
      }
    }
  }
  res.unshift([])
  return res
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值