【算法】八月算法打卡

news2024/11/18 6:31:47

2022-08-01

低配版 promise

class MyPromise {
  constructor(executor) {
    // 成功回调队列
    this._resolveQueue = [];
    // 失败回调队列
    this._rejectQueue = [];

    let resolve = (val) => {
      while (this._resolveQueue.length) {
        const callback = this._resolveQueue.shift();
        callback(val);
      }
    }

    let reject = (val) => {
      while (this._rejectQueue.length) {
        const callback = this._rejectQueue.shift();
        callback(val);
      }
    }

    // 创建实例对象时,立即执行 executor 并传入 resolve 和 reject
    executor(resolve, reject);
  }

  then = (resolveFunc, rejectFunc) => {
    this._resolveQueue.push(resolveFunc);
    this._rejectQueue.push(rejectFunc);
  }
}

// 测试
const p = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('result');
  }, 2000);
});

p.then(res => console.log(res)); // result
  • Promise 构造方法接收一个 executor(),在 new Promise() 时立即执行该任务。
  • executor() 内部的异步任务会被放入到 宏/微任务队列,等待执行。
  • then()被执行,收集成功/失败回调,放入成功/失败队列。
  • executor()的异步任务被执行,触发resolve/reject,从成功/失败队列中取出回调依次执行。

2022-08-02

Promise A+规范 + then 链式调用

const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class MyPromise {
  constructor(executor) {
    this.status = PENDING;
    this.resolveQueue = [];
    this.rejectQueue = [];
    let resolve = (val) => {
      if (this.status !== PENDING) return;

      this.status = FULFILLED;

      while (this.resolveQueue.length) {
        let callback = this.resolveQueue.shift();
        callback(val);
      }
    }

    let reject = (val) => {
      if (this.status !== PENDING) return;

      this.status = REJECTED;

      while (this.rejectQueue.length) {
        let callback = this.rejectQueue.shift();
        callback(val);
      }
    }
    executor(resolve, reject);
  }
  then = (resolveFunc, rejectFunc) => {
    return new MyPromise((resolve, reject) => {
      let successFunc = (val) => {
        try {
          let x = resolveFunc(val);
          x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
        } catch (error) {
          reject(error);
        }
      }
      this.resolveQueue.push(successFunc);

      let errorFunc = (error) => {
        try {
          let x = rejectFunc(error);
          x instanceof MyPromise ? x.then(resolve, reject) : reject(x);
        } catch (error) {
          reject(error);
        }
      }
      this.rejectQueue.push(errorFunc);
    })
  }
}
// 测试
const p1 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  }, 500);
})

p1.then(res => {
  console.log(res)
  return 2
}).then(res => {
    console.log(res)
    return 3
}).then(res => {
    console.log(res)
})
//输出 1 2 3

2022-08-03

值穿透、状态变更

// 暂停
const PENDING = 'pending'
// 完成
const FULFILLED = 'fulfilled'
// 拒绝
const REJECTED = 'rejected'
class Mypromise {
    constructor(executor) {
        this.status = PENDING;
        this.preValue = null;
        this.resolveQueue = [];
        this.rejectQueue = [];
        let resolve = (val) => {
            if (this.status !== PENDING) return;
            this.status = FULFILLED;

            this.preValue = val;

            while (this.resolveQueue.length) {
                let callback = this.resolveQueue.shift();
                callback(val);
            }
        }

        let reject = (val) => {
            if (this.status !== PENDING) return;
            this.status = REJECTED;

            this.preValue = val;

            while (this.rejectQueue.length) {
                let callback = this.rejectQueue.shift();
                callback(val);
            }
        }
        executor(resolve, reject);
    }
    then = (resolveFunc, rejectFunc) => {
        return new MyPromise((resolve, reject) => {

            typeof resolveFunc !== 'function' ? resolveFunc = value => value : null;
            typeof rejectFunc !== 'function' ? rejectFunc = reason => {
                throw new Error(reason instanceof Error ? reason.message : reason)
                } : null;

            let successFunc = (val) => {
                try {
                    let x = resolveFunc(val);
                    x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
                } catch (error) {
                    reject(error);
                }
            }
            let errorFunc = (error) => {
                try {
                    let x = rejectFunc(error);
                    x instanceof MyPromise ? x.then(resolve, reject) : reject(x);
                } catch (error) {
                    reject(error);
                }
            }

            switch (this.status) {
                case PENDING:
                    this.resolveQueue.push(successFunc);
                    this.rejectQueue.push(errorFunc);
                    break;
                case FULFILLED:
                    resolveFunc(this.preValue);
                    break;
                case REJECTED:
                    rejectFunc(this.preValue);
                    break;
            }
        })
    }
}

2022-08-04

兼容同步任务

const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {
    constructor(executor) {
        this.status = PENDING;
        this.preval = null;
        this.resolveQueue = [];
        this.rejectQueue = [];

        let resolve = (val) => {
           const run = () => {
               if (this.status !== PENDING) return;

               this.status = FULFILLED;
               this.preval = val;

               while (this.resolveQueue.length) {
                   let callback = this.resolveQueue.shift();
                   callback(val);
               }
           }
           setTimeout(run)
        }
        let reject = (val) => {
            const run = () => {
                if (this.status !== PENDING) return;

                this.status = REJECTED;
                this.preval = val;

                while (this.rejectQueue.length) {
                    let callback = this.rejectQueue.shift();
                    callback(val);
                } 
            }
            setTimeout(run)
        }

        executor(resolve, reject);
    }
    then = (resolveFunc, rejectFunc) => {
        return new MyPromise((resolve, reject) => {

            typeof resolveFunc !== 'function' ? resolveFunc = val => val : null;
            typeof rejectFunc !== 'function' ? rejectFunc = reason => {
                throw new Error(reason instanceof Error ? reason.message : reason)
            } : null;

            let successFunc = (val) => {
                try {
                    let x = resolveFunc(val);
                    x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
                } catch (error) {
                    reject(error);
                }
            }

            let errorFunc = (val) => {
                try {
                    let x = rejectFunc(val);
                    x instanceof MyPromise ? x.then(resolve, reject) : reject(x);
                } catch (error) {
                  reject(error);
                }
            }

            switch (this.status) {
                case PENDING:
                    this.resolveQueue.push(successFunc);
                    this.rejectQueue.push(errorFunc);
                    break;
                case FULFILLED:
                    resolveFunc(this.preval);
                    break;
                case REJECTED:
                    rejectFunc(this.preval);
                    break;
            }
        })
    }
}

2022-08-05

promise其他方法

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
    constructor(executor) {
        this.status = PENDING;
        this.val = null;
        this.resolveQueue = [];
        this.rejectQueue = [];

        let resolve = (val) => {
            const run = () => {
                if (this.status !== PENDING) return;

                this.status = FULFILLED;
                this.val = val;

                while (this.resolveQueue.length) {
                    let callback = this.resolveQueue.shift();
                    callback(val);
                }
            }
            setTimeout(run);
        }

        let reject = (val) => {
           const  run = () => {
               if (this.status !== PENDING) return;

               this.status = REJECTED;
               this.val = val;

               while (this.rejectQueue.length) {
                   let callback = this.rejectQueue.shift();
                   callback(val);
               }
           }
           setTimeout(run);
        }
        executor(resolve, reject)
    }
    then = (resolveFunc, rejectFunc) => {
        return new MyPromise((resolve, reject) => {
            typeof resolveFunc !== 'function' ? resolveFunc = val => val : null;
            typeof rejectFunc !== 'function' ? rejectFunc = reason => {
                throw new Error(reason instanceof Error ? reason.message : reason);
            } : null;

            let successFunc = (val) => {
                try {
                    let x = resolveFunc(val);
                    x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
                } catch (e) {
                    reject(e);
                }
            }
            let errorFunc = (val) => {
                try {
                    let x = rejectFunc(val);
                    x instanceof MyPromise ? x.then(resolve, reject) : reject(x)
                } catch (e) {
                    reject(e);
                }
            }

            switch (this.status) {
                case PENDING:
                    this.resolveQueue.push(successFunc);
                    this.rejectQueue.push(errorFunc);
                    break;
                case FULFILLED:
                    resolveFunc(this.val);
                    break;
                case REJECTED:
                    rejectFunc(this.val);
                    break;
            }
        })
    }

    static resolve(value) {
        if (value instanceof MyPromise) return value;
        return new MyPromise(resolve => resolve(value))
    }
    static reject(reason) {
        return new MyPromise((resolve, reject) => reject(reason))
    }
    static all() {}
    static race() {}
    // catch方法其实就是执行一下then的第二个回调
    catch(rejectFunc) {
        return this.then(undefined, rejectFunc)
    }
    finally(callback) {
        return this.then(
            value => MyPromise.resolve(callback()).then(() => value),             // MyPromise.resolve执行回调,并在then中return结果传递给后面的Promise
            reason => MyPromise.resolve(callback()).then(() => { throw reason })  // reject同理
        )
    }
}

2022-08-06

判断是否为回文子串

function test(str) {
    let len = str.length;
    let l = 0;
    let r = len - 1;
    let flag = true;
    while (l < r && flag) {
        if (str.charAt(l) != str.charAt(r)) flag = false;
        l++;
        r--;
    }
    return flag;
}

判断是否为回文数

在这里插入图片描述

function test(num) {
   if (num < 0 || num % 10 == 0) return false;
   let temp = num;
   let reverse = 0;
   while(temp != 0) {
       let x = temp % 10;

       temp = Math.floor(temp / 10);
       reverse = reverse * 10 + x;
   }
   return  reverse == num;
}
console.log(test(32))

最长回文子串

在这里插入图片描述

解法:双指针

回文子串分为两种

  • 奇数子串 aba
  • 偶数子串 abba

取中心点向俩边扩散

  • 奇数中心点 左:i 右:i
  • 偶数中心点 左:i 右:i+1
let longestPalindrome = function (s) {
    let max = "";
    for (let i = 0; i < s.length; i++) {
        // 奇数子串
        helper(i, i);
        // 偶数子串
        helper(i, i+1);
    }
    function helper(l, r) {
        // 找左右相同字符串
        while (l >= 0 && r < s.length && s[l] == s[r]) {
            l--;
            r++;
        }
        // 找到回文子串后,由于 while 再执行了一轮循环,故需要对指针进行回退,即 (l + 1) (r - 1)
        const maxStr = s.slice(l + 1, r + 1 - 1);
        if (maxStr.length > max.length) max = maxStr;
    }
    return max;
}

let s = "abbaabbaaccaabbaab";
console.log(longestPalindrome(s));

2022-08-07

Z字形变换

在这里插入图片描述

// 0         | 6        12
// 1       5 | 7     11 13
// 2   4     | 8  10
// 3         | 9

let test = (s, row) => {
    if (row <= 1 || row >= s.length) return s;

    // 周期
    let space = 2 * row - 2;
    let result = "";
    for (let i = 0; i < row; i ++) { // 层数循环(纵向)
        for (let j = i; j < s.length; j += space) { // 单层循环 (横向)
            result += s.charAt(j);

            let mod = j % space;
            // 非第一行和最后一行
            if (mod > 0 && i != 0 && i != row - 1) {
                // 在周期范围内,当前位置j 到下一个位置的距离
                // 类似计算 1 =》 5, 7 =》 11 之间的距离
                let index = j + 2 * (row - i - 2);
                result += s.charAt(index);
            }
        }
    }
    return result;
}
let str = 'PAYPALISHIRING';
console.log(test(str, 3)) // PAHN APLSIIG YIR
// P   A   H   N
// A P L S I I G
// Y   I   R
// PAHN APLSIIG YIR

console.log(test(str, 4)) // PIN ALSIG YAHR PI
// P      I       N
// A    L S     I G
// Y  A   H   R
// P      I
// PIN ALSIG YAHR PI

加一

在这里插入图片描述

function test(digits) {
   const len = digits.length;
   for (let i = len - 1; i >= 0; i--) {
       digits[i]++;
       digits[i] %= 10; // 10 % 10 = 0 (1 ~ 9) % 10 = (1 ~ 9)
       // 没有进位,直接返回
       if (digits[i] != 0) return digits;
       // 来到这里:说明前者加了1 导致要进位 故读取下一位进行加一
   }
   // 来到这里:说明 数组中所有值都为 0, 并且还少一位
   digits = [...Array(len + 1)].fill(0);
   // 补齐
   digits[0] = 1;
   return  digits;
}
console.log(test([9, 9, 9]))

2022-08-08

字符串转换整数

在这里插入图片描述

解法:

    function test(s) {
        let flag = 1;
        let res = 0;
        let i = 0;
        // 过滤空格
        while (s.charAt(i) === '') i++;

        // 判断正负
        if (i < s.length && s.charAt(i) === '+') {
            i++;
        } else if (x < s.length && s.charAt(i) === '-') {
            i++;
            flag = -1;
        }

        while(i < s.length && s.charAt(i) <= '9' && s.charAt(i) >= '0') {
            let tmp = s.charAt(i) - 0;
            res = res * 10 + tmp;

            if (res <= -2147483648) return -2147483648;
            else if (res >= 2147483647) return 2147483647;
        }
        return res;
    }

补充:

// 去除字符串内所有的空格:
str = str.replace(/\s*/g,"");
//去除字符串内两头的空格:
str = str.replace(/^\s*|\s*$/g,"");
// 去除字符串内左侧的空格:
str = str.replace(/^\s*/,"");
// 去除字符串内右侧的空格:
str = str.replace(/(\s*$)/g,"");

盛最多水的容器

在这里插入图片描述

解法:双指针

  • 从两端位置向中间靠拢,计算当前面积。
  • 比较当前两端高度值,高度小的一边向中间靠拢。
  • 当两端重合时,结束,输出最大面积
function test(arr) {
    let l = 0;
    let r = arr.length - 1;
    let max = 0;
    while(l < r) {
        let maxArea = (r - l) * Math.min(arr[l], arr[r]);
        if (maxArea > max) max = maxArea;
        arr[l] < arr[r] ? l++ : r--;
    }
    return max;
}

2022-08-09

罗马数字转整数

在这里插入图片描述

解法:

  • 根据罗马数字的特点:从左到右,值依次递减。
  • 如果当前位置小于下一个值,则要减去该值,反则累加
var romanToInt = function(s) {
  let obj = {
      "M": 1000,
      "D": 500,
      "C": 100,
      "L": 50,
      "X": 10,
      "V": 5,
      "I": 1
  }
  let res = 0;
  for (let i = 0; i < s.length-1; i++) {
      if (obj[s.charAt(i)] >= obj[s.charAt(i+1)]) {
          res += obj[s.charAt(i)]
      } else {
          res -= obj[s.charAt(i)]
      }
  }
  return res + obj[s.charAt(s.length-1)];
}

数字转罗马数字

在这里插入图片描述

解法:贪心算法

  • 对整数做减法,每次都减去符合罗马数的最大值
var intToRoman = function(num) {
    let arr = [
        {
            value: 1000,
            char: "M"
        },{
            value: 900,
            char: "CM"
        },{
            value: 500,
            char: "D"
        },{
            value: 400,
            char: "CD"
        },{
            value: 100,
            char: "C"
        },{
            value: 90,
            char: "XC"
        },{
            value: 50,
            char: "L"
        },{
            value: 40,
            char: "XL"
        },{
            value: 10,
            char: "X"
        },{
            value: 9,
            char: "IX"
        },{
            value: 5,
            char: "V"
        },{
            value: 4,
            char: "IV"
        },{
            value: 1,
            char: "I"
        }
    ];
    let res = "";
    for (let i = 0; i < arr.length && num >= 0; ++i) {
        // 减去最大值
        while (num >= arr[i].value) {
            num -= arr[i].value;
            res += arr[i].char;
        }
    }
    return res;
};

2022-08-10

最长前缀码

在这里插入图片描述

解法:

  • 取最短的字符串为基本比较的字符串
  • 遍历数组(从第二个位置开始遍历)
  • 遍历字符串,每一个位置进行比较,不等则结束比较
var longestCommonPrefix = function(strs) {
    if(strs.length == 0) return "";
    // 排序(降序)
    strs.sort((a, b) => a.length - b.length);
    // 取标志点
    let ans = strs[0];
    // 遍历数组(从第二个开始)
    for(let i = 1;i < strs.length; i++) {
        let j = 0;
        // 遍历字符串
        for(;j < ans.length && j < strs[i].length; j++) {
            if(ans[j] != strs[i][j]) break;
        }
        ans = ans.substr(0, j);
        if(ans === "") return ans;
    }
    return ans;
};

最接近的三数之和

在这里插入图片描述

解法:采用双指针的方式

  • 对数组进行升序排序
  • 遍历数组,从第 i 点开始作为三个值的其中一个,将左指针定位到第 i + 1,右指针定位到 nums.length - 1;
  • 每次遍历,计算当前三者值,与目标值(target)更接近则保存该值
  • 比目标值小,则左指针右移。
  • 比目标值大,则右指针左移。
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var threeSumClosest = function(nums, target) {
    // 升序排
    nums.sort((a, b) => a - b);
    // 假设前三最接近目标值
    let ans = nums[0] + nums[1] + nums[2];
    for (let i = 0; i < nums.length; i++) { // 遍历数组
        let l = i + 1; // 左指针
        let r = nums.length - 1; // 右指针
        while(l < r) {
            // 计算此轮循环的当前值
            let sum = nums[i] + nums[l] + nums[r];
            // 比较,谁更接近目标值
            if (Math.abs(target - sum) < Math.abs(target - ans)) ans = sum;
            // 比目标值大
            if (sum > target) r--;
            // 比目标值小
            else if (sum < target) l++;
            // 等于目标值,直接返回
            else return ans
        }
    }
    return ans;
};

2022-08-11

四数之和

在这里插入图片描述

解法:双指针

  • 跟三数和类型,只不过在多一层循环
function test(nums, target) {
  let res = [];

  // 特殊情况判断
  if (nums == null || nums.lengths < 4) return res;

  // 升序
  nums.sort((a, b) => a - b);
 
  let len = nums.length;
  for (let a = 0; a < len - 3; a++) {
    
    // 确保第一个元素变了,并固定其值
    if (a > 0 && nums[a] == nums[a - 1]) continue;

    // 固定第二值
    for (let b = a + 1; b < len - 2; b++) {
       // 确保第二个元素变了,并固定其值
       if (b > a + 1 && nums[b] == nums[b - 1]) continue;
       
       // 确认双指针
       c = b + 1;
       d = len - 1;

       while (c < d) {
          // 计算此时四个值
          let sum = nums[a] + nums[b] + nums[c] + nums[d];
          if (sum < target) {
            c++;
          }else if (sum > target) {
            d--;
          } else {
            res.push([nums[a], nums[b], nums[c], nums[d]]);

            // 对左右指针进行移动
            while (c < d && nums[c] == nums[c +1]) {
                c++;
            }
            while(c < d && nums[d] == nums[d - 1]) {
                d--
            }
            c += 1;
            d -= 1;
          }
       }
    }
  }
  return res;
}
let nums =  [1, 0, -1, 0, -2, 2];
let target = 0;
console.log(test(nums, target))

有效括号

在这里插入图片描述

解法:使用栈

/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function (str) {
  let stack = [];
  for (let i = 0; i < str.length; i++) {
    let tmp = str.charAt(i);
    // 入栈
    if (tmp == '(' || tmp == '{' || tmp == '[') {
      stack.push(tmp);
    } else {
      let top = stack[stack.length == 0 ? 0 : stack.length - 1]
      if (tmp == ')' && stack.length != 0 && top == '(') {
        stack.pop();
      } else if (tmp == '}' && stack.length != 0 && top == '{') { 
        stack.pop();
      } else if (tmp == ']' && stack.length != 0 && top == '[') {
        stack.pop();
      } else {
        return false;
      }
    }
  }
  console.log(stack);
  return stack.length == 0;
};

2022-08-12

括号生成

在这里插入图片描述

  • 解法:回溯算法(树形结构)

在这里插入图片描述

结束递归条件:str.length == 2n;

左括号个数以及右括号个数为 n: n;

添加左括号的条件:只要当前有剩余左括号,就添加。

添加右括号的条件:只要右括号剩余数量比左括号剩余数量多,就添加。

  /**
   * 
   * @param {Number} l 左括号个数 
   * @param {*} r 右括号个数
   * @param {*} str 当前字符串
   * @returns 
   */
  const dfs = (l, r, str) => { 
    // 结束递归
    if (str.length == 2 * n) { 
      res.push(str);           
      return;                  
    }

    // 左括号还有,继续添加左括号
    if (l > 0) dfs(l - 1, r, str + "(");
    
    // 右括号比左括号剩的多,才能选右括号
    if (l < r) dfs(l, r - 1, str + ")"); 
  };

  dfs(n, n, "");
  return res;
};

电话号码的字母组合

在这里插入图片描述

  • 解法:回溯算法(树形结构)

结束递归条件 str.length == digits.length;

/**
 * @param {string} digits
 * @return {string[]}
 */
var letterCombinations = function(digits) {
    let list = [];
    if (digits.length == 0) return [];
    let obj = {
            "2": "abc",
            "3": "def",
            "4": "ghi",
            "5": "jkl",
            "6": "mno",
            "7": "pqrs",
            "8": "tuv",
            "9": "wxyz"
    }
    /**
     * @param {string} str 当前字符串
     * @return {} index 当前 digits 对应的下标
     */
    var dfs = function (str, index) {
        // 符合条件,结束递归
        if (str.length == digits.length) {
           list.push(str);
           return;
        }
        // 取出数字对应的字符串
        let s = obj[digits.charAt(index)];
        for(let i = 0; i < s.length; i++) {
          dfs(str + s.charAt(i), index + 1);
        }
    }
    dfs("", 0);
    return list;
};

2022-08-13

删除数组中重复的数字

在这里插入图片描述

在这里插入图片描述

解法:双指针fastslow

起始点:俩指针都从数组下标为1开始

结束标志:到达数组尾部

slow 所指位置代表从 0 ~ (slow - 1) 没有重复的数字,slow位置代表当前可能需要被替换

fast 代表下一个数字

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    let len = nums.length;
    if (len == 0) return [];
    
    let fast = 1;
    let slow = 1; // 待替换位置
    while (fast < len) {
        
        if (nums[fast] !== nums[fast - 1]) {
            // 当前 slow 前(包括slow)都不重复
            nums[slow] = nums[fast];
            // 指向下一个待替换位置
            ++slow;
        }
        // 继续前进
        ++fast;
    }
    return slow
};

串联所有单词的子串

在这里插入图片描述

解法:

  • 遍历 s 从 i = 0 开始截取 words.length * words[0].length 长度的字符串curS
  • 在遍历 words 根据 单词长度(words)从curS中截取 words[j].length的字符串curChild
  • 判断 words 是否存在该单词 curChild,存在则移除,再次截取,进行判断
  • 不存在,则该起始位置不对
/**
 * @param {string} s
 * @param {string[]} words
 * @return {number[]}
 */
var findSubstring = function(s, words) {
   if (words.length == 0) return [];

   // 计算单词总长度
   let wordsLen = words.length * words[0].length;
   if (s.length < wordsLen) return  [];

   let resArr = [];
   // 每个单词长度
   let childLen = words[0].length;

   // 拷贝
   let wordsCopy;
   for (let i = 0; i <= s.length - wordsLen; i++) {
       // 从匹配串截取 单词总长度 的字符串
       let curS = s.slice(i, i+wordsLen);
       console.log("curS字符串为", curS);

       let is_Target = true;
       wordsCopy = [...words];

       for (let j = 0; j <= wordsLen-childLen; j+= childLen) {
           // 截取第 j 个单词出来
           let curChild = curS.slice(j, j+childLen);
           console.log(`从 curS 截取的第${j + 1}个单词为`, curChild);

           // 判断在 wordsCopy 中是否存在
           let index = wordsCopy.indexOf(curChild);
           if (index !== -1) {
               // 存在,移除
               wordsCopy.splice(index, 1);
           } else {
               is_Target = false;
               break;
           }
       }
       console.log("-----------------");
       if (is_Target) resArr.push(i);
   }
   return resArr;
};

2022-08-14

移除元素

在这里插入图片描述

在这里插入图片描述

解法:双指针(快慢指针)跟 删除数组中重复的数字类似

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

合并K个升序链表

在这里插入图片描述

解法:

  • 遍历 list 数组中的每一条链表,根据当前链表头获取其最小值,并把该值插入到新的链表中

  • 并且在该链表找到该最小值时,需要将链表下移(list[minIndex] = list[minIndex].next),为下一次寻找最小值做准备

    在这里插入图片描述

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode[]} lists
 * @return {ListNode}
 */
var mergeKLists = function(lists) {
   // 头部
   let head = null;
   let temp = null;
   while (true) {
       // 当前最小值下标
       let minIndex = -1;
       for (let i = 0; i < lists.length; i++) {
          if (lists[i] != null) {
              if (minIndex == -1) { // 初始化
                  minIndex = i;
              } else {
                  if (lists[i].val < lists[minIndex].val) minIndex = i;
              }
          }
       }
       if (minIndex == -1) break; // 结束

       // 找到最小值
       if (head == null) {
           head = lists[minIndex];
           temp = head;
       } else {
           temp.next = lists[minIndex];
           // 为下一次循环做准备
           temp = temp.next;
       }
       // 把当前最小值的位置下移(未下一次寻找最小值做准备)
       lists[minIndex] = lists[minIndex].next;
   }
   return head;
};

2022-08-15

实现strStr()

在这里插入图片描述

解法:遍历字符串,进行比较

var strStr = function(haystack, needle) {
    let hayLen = haystack.length;
    let needlen = needle.length;
    if(needlen == 0) return 0;
    let i = 0;
    let j = 0;
    while(i < hayLen && j < needlen) {
        if (haystack.charAt(i) == needle.charAt(j)) {
            i++;
            j++;
        } else {
            // i - j 回退之前前进的距离 j +1 在前进一个位置,变相遍历 haystack
            i = i - j + 1;
            j = 0;
        }
    }
    if (j == needlen) return i - j;
    return  -1;
};
console.log(strStr("Hello", "ll"));

2022-08-16

俩数整除

在这里插入图片描述

解法:由于无法使用相除,可以使用相减,但由于时间限制,因此,可以采用左移的形式,计算出被除数可以被减去最大数.

var divide = function(dividend, divisor) {
  if (divisor === 0) return Infinity;
  if (dividend === 0) return 0;
  if (dividend === -2147483648 && divisor === -1) return 2147483647;

  let res = 0;
  let flag = '';
  if (dividend < 0 && divisor > 0 || dividend > 0 && divisor < 0) flag = '-';
  
  dividend = Math.abs(dividend);
  divisor = Math.abs(divisor);
  
  while (dividend >= divisor) {
      let temp = divisor, m = 1;

      // 计算出最大值
      while (temp <= (dividend >> 1)) { 
          temp <<= 1; // temp = temp * 2;
          m <<= 1; // m = m * 2;
      }

      dividend -= temp;
      res += m;

      // dividend 可能还可以再减去多个 divisor,故再次执行一次 while
  }

  return parseInt(flag + res);
};
console.log(divide(1, 1))

搜索插入位置

在这里插入图片描述

解法:双指针

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

2022-08-17

下一个排列

在这里插入图片描述

解法:

  • 从数组的倒数第二个开始寻找 arr[i] < arr[i + 1];找到后,将其保存在变量 temp
  • 如找到该值,则再次从数组倒数第一个向左找到第一个比temp小的数,两者进行交换位置,并在 temp所在位置(i)后面的所有数字倒叙排
  • 如未找到,则说明已经是最大值,直接倒叙排
var nextPermutation = function(arr) {
    let swap = (arr, i, j) => {
		let temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
	let reverse = (arr, start) => {
		let left = start;
		let right = arr.length - 1;
		while (left < right) {
			swap(arr, left, right);
			left++;
			right--;
		}
	}

    let len = arr.length;
    let i = len - 2; // 倒数第二个数开始

	// 找到 左边值小于右边值
	while(i >= 0 && arr[i] >= arr[i+1]) {
		i--;
	}
	if (i >= 0) { // 找到
		let j = len - 1; // 倒数第一个数开始

		// 再从右到左找比arr[i] 小的数
		while(j >= 0 && arr[i] >= arr[j]) {
			j--;
		}
		// 交换
		swap(arr, i, j);
	}
    
	// 后面值倒排
	reverse(arr, i+1);
	return arr;
};

2022-08-18

最长有效括号

在这里插入图片描述

解法:

初始栈时,在栈底设置一个哨兵 -1

  • 遍历字符串 s
    • 每次遇到 ( 直接把下标压入栈中
    • 若遇到 ) 则要从栈顶取出元素
      • 取出元素后,判断栈是否为空
        • 为空,说明刚才取出的元素是哨兵(右括号)。此时说明从当前哨兵为起始点,匹配最长的括号已经结束。把刚才从s出来的字符串对应数组下标存入到栈中,代表新的哨兵(右括号)。
        • 不为空,说明,可以匹配成功,更新最长有效括号长度(当前下标 - 取出栈顶的下标值)
/**
 * @param {string} s
 * @return {number}
 */
var longestValidParentheses = function(s) {
    if (s.length == 0) return 0;

    let res = [-1];
    let max = 0;
    let len = s.length;
    for (let i = 0; i < len; i++) {
        let temp = s.charAt(i);
        if (temp == "(") {
            res.push(i)
        } else {
            res.pop();

            if (res.length == 0) {
              res.push(i);
            } else {
               max  = Math.max(max, i - res[res.length - 1])
            }
        }
    }
    return max;
};

2022-08-19

最后一个单词长度

在这里插入图片描述

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLastWord = function(s) {
     
     let len = s.length;
     let i = len - 1;
     let num = 0;
     while (i >= 0 && s.charAt(i) == " ") {
         i--;
     }
     while  (i >= 0 && s.charAt(i) != " ") {
        ++num;
        --i;
     }
     return num;
};

2022-08-20

俩两交换链表中的节点

在这里插入图片描述

解法:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var swapPairs = function(head) {
   const dummyHead = new ListNode(0);
    dummyHead.next = head;
    let temp = dummyHead;
    while (head && head.next) {
        const node1 = head;
        const node2 = head.next;

        temp.next = node2;
        node1.next = node2.next;
        node2.next = node1;

        temp = node1;
        head = head.next;
    }
    return dummyHead.next;
};

2022-08-21

反转链表

在这里插入图片描述

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    // 当前节点
    let cur = head;
    // 上一个节点
    let prev = null;
    while(cur !== null) {
      // 下一个节点
      let next = cur.next;
      // 当前节点next指向上一个节点
      cur.next = prev;
      
      // 更新
      prev = cur;
      cur = next;
    }
    return prev;
};

2022-08-22

二进制求和

在这里插入图片描述

var addBinary = function(a, b) {
    let add = 0
    let sum = []
    for(let i = a.length -1, j = b.length -1; i >= 0 || j >= 0; i--, j--) {
        let num1 = +a[i] || 0
        let num2 = +b[j] || 0
        sum.unshift(num1 ^ num2 ^ add)
        add = num1 + num2 + add > 1 ? 1 : 0
        
    }
    if (add === 1) sum.unshift(1)
    return sum.join('')
};

K个一组翻转链表

在这里插入图片描述

解法:跟反转链表一样,只不过是将链表切分成多个。关键点在于多个链表如何进行连接

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} k
 * @return {ListNode}
 */
var reverseKGroup = function(head, k) {
      if (head == null) return head;
      let start = head;
      let end = head;

      // start ~ end 反转链表
      let reverse = (start, end) => {
          let prevNode = end;
          let currentNode = start;
          let nextNode = start;
          while(currentNode != end) {
              let nextNode = currentNode.next;
              
              // 当前节点指向上一个节点
              currentNode.next = prevNode;

              // 指向下一个结点
              currentNode = nextNode;
              // 更新上一个结点
              prevNode = currentNode;
          }
          // 返回链表的起始头
          return prevNode;
      }

     //  获取 k 个结点 的起始头
     for (let i = 0; i < k; i++) {
            if (end == null) return head;
            end = end.next;
     }

    // 更新反转后链表的起始头
    let newHead = reverse(start, end);
    // 递归,并连接之前递归结果
    start.next = reverseKGroup(end, k);
    return newHead;
};

2022-08-23

移除链表元素

在这里插入图片描述

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

2022-08-26

二叉树的中序遍历

在这里插入图片描述

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var inorderTraversal = function(root,array=[]) {
  if(root){
     inorderTraversal(root.left,array);
     array.push(root.val);
     inorderTraversal(root.right,array);
  }
  return array;
  
};

2022-08-27

查找排序数组中元素的第一个和最后一个

在这里插入图片描述

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var searchRange = function(nums, target) {
    let searchIndex = (nums, target, lower) => {
        let left = 0;
        let right = nums.length - 1;
        let res = -1;
        while (left <= right) {
            let mid = parseInt((right - left) / 2 + left);
            if (target == nums[mid]) {
                res = mid;
                if (lower) right = mid - 1; // 开始位置,缩小左区域
                if (!lower) left = mid + 1; // 结束位置,缩小右区域
            } else if (target < nums[mid]) {
                right = mid - 1;
            } else {
                left = mid + 1
            }
        }
        return res;
    }
    let start = searchIndex(nums, target, true);
    let end = searchIndex(nums, target, false);
    return [start, end];
}

2022-08-28

x的平方根

在这里插入图片描述

/**
 * @param {number} x
 * @return {number}
 */
var mySqrt = function(x) {
    let b = 1;
    while(x / b >= b) {
        b++;
    }
    return b - 1;
};

2022-08-29

爬楼梯

在这里插入图片描述

解法:递归

/**
 * @param {number} n
 * @return {number}
 */
var climbStairs = function(n) {
    const dp = [];
    dp[0] = 1;
    dp[1] = 1;
    for(let i = 2; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    return dp[n];
};

2022-08-30

删除排序链表中的重复元素

在这里插入图片描述

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var deleteDuplicates = function(head) {
    if (!head)  return head;
    
    let cur = head;
    while (cur.next) {
        if (cur.val === cur.next.val) {
            cur.next = cur.next.next;
        } else {
            cur = cur.next;
        }
    }
    return head;
};

2022-08-31

有效数独

在这里插入图片描述

解法:

计算每个数字保存在表格中第几行,第几列,第几个盒子。并将其保存在set数据结构中,在保存前,判断set是否存在该值,若存在,则该数独无效。反之遍历结束,则数独有效

/**
 * @param {character[][]} board
 * @return {boolean}
 */
var isValidSudoku = function(board) {
    let set = new Set();
    for (let i = 0; i < 9; i++) {
        for (let j = 0; j < 9; j++) {
            if (board[i][j] != ".") {
                let val = board[i][j];
                let boxIndex = Math.floor(i / 3) * 3 + Math.floor(j / 3);
                
                let r =  val + "in row" + i;
                let c = val + "in col" + j;
                let b = val + "in box" + boxIndex;

                if (set.has(c) || set.has(r) || set.has(b)) {
                    return false;
                } else {
                    set.add(r);
                    set.add(c);
                    set.add(b);
                }
            }
        }
    }
    return true;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/96239.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【iOS】对象,消息,运行期

文章目录对象&#xff0c;消息&#xff0c;运行期属性属性特质原子性方法名在对象内部尽量直接访问实例变量对象等同性特定类所具有的等同性判断等同性判定的执行深度容器中可变类的等同性以“类族模式”隐藏实现细节创建类族Cocoa里的类族在既有类中使用关联对象存放自定义数据…

原型,原型链,原型的继承

原型的作用? 1.节省内存空间 2.实现数据共享(继承) 什么是原型? 任何一个函数都有propotype属性,它本身是一个对象,我们称之为原型 构造函数,实例化对象与原型之间的关系? 1.任何一个函数都有prototype属性,它本身是一个对象,我们称之为原型 2.构造函数也是函数,也都…

C语言中头文件(.h)编写,头文件的包含<>和““很大不同

头文件书写技巧 1、头文件主要作用&#xff0c;提前声明函数&#xff0c;因为在c语言中必须先声明或定义才能使用 2、在使用到.c文件中需要把这个.h文件进行包含格式是#include <h文件>或#include "h文件名"&#xff0c;但**强烈建议用引号**&#xff0c;尖括…

【码极客精讲】do while语句

上次讲了while语句&#xff0c;这次讲一下do while语句。 do...while 循环是 while 循环的变体。在检查while()条件是否为真之前&#xff0c;该循环首先会执行一次do{}之内的语句&#xff0c;然后在while()内检查条件是否为真&#xff0c;如果条件为真的话&#xff0c;就会重复…

binder调用流程分析

binder是一个非常好的跨进程通信工具&#xff0c;Android对其进行了各种封装&#xff0c;虽然我们用起来简单&#xff0c;但是理解起来却比较困难。 1.自己设计一个跨进程通信机制 在理解binder之前呢&#xff0c;首先我们想一下&#xff0c;如果我们自己设计一个跨进程通信的…

关于树形dp问题的解决

文章目录解决套路案例展示一、二叉树的最大深度二、判断是不是平衡二叉树三、判断是不是二叉搜索树四、判断是否是满二叉树五、二叉树节点间的最大距离六、派对的最大快乐值解决套路 实际上就是设计一个递归函数&#xff0c;该递归函数一定要包含 basecase&#xff0c;即让函数…

[附源码]Python计算机毕业设计高校选课系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等…

[附源码]Python计算机毕业设计共享自习室管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等…

【C++】STL-string的使用

文章目录1.为什么学习string类&#xff1f;1.1 C语言中的字符串OJ题目1&#xff1a;字符串相加2.标准库中的string类2.1 string类(了解)总结&#xff1a;2.2 string类的常用接口说明1. string类对象的常见构造2.string类对象的容量操作max_sizereserve和resize3. string类对象的…

Spirng 痛苦源码学习(三)——Spring中的几个核心老大

文章目录前言一、基础接口1.Resource2.ResourceLoader3.BeanFactory&#xff08;1&#xff09;总览&#xff08;2&#xff09;继承如下&#xff08;3&#xff09;重要的工厂4. ApplicationContext前言 一开始学习spring我们首先还是要搞清楚他的整体架构&#xff0c;就是他是干…

[附源码]Node.js计算机毕业设计互联网教学平台Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

C++ Reference: Standard C++ Library reference: Containers: map: multimap: end

C官网参考链接&#xff1a;https://cplusplus.com/reference/map/multimap/end/ 公有成员函数 <map> std::multimap::end C98 iterator end(); const_iterator end() const; C11 iterator end() noexcept; const_iterator end() const noexcept;返回指向结束的iterator …

HTTP简介(GET,POST)

HTTP简介(GET,POST) 简介 HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff0c;规定了浏览器和服务器之间数据传输的规则。 演示 HTTP协议的特点 基于TCP协议: 面向连接&#xff0c;安全 TCP是一种面向连接的(建立连接之前是需要经过三次握手)、可靠的、基于…

[附源码]Python计算机毕业设计SSM基于Java家庭财务管理系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

LeetCode 297. 二叉树的序列化与反序列化

今天早上睡起来刷了这么一道题&#xff0c;二叉树的序列化和反序列化 大概意思就是给你一个二叉树&#xff0c;把他转成一个字符串&#xff0c;中间的自定义规则由你定&#xff0c;再根据这个字符串去还原这个二叉树&#xff0c;这道题的话思路不难&#xff0c;写起来有的细节…

【云原生 | Kubernetes 实战】13、K8s 常见的存储方案及具体应用场景分析(上)

目录 K8s 持久化存储 一、k8s 持久化存储&#xff1a;emptyDir 二、k8s 持久化存储&#xff1a;hostPath 三、k8s 持久化存储&#xff1a;nfs 3.1 搭建 nfs 服务 3.2 创建Pod&#xff0c;挂载 NFS 共享出来的目录 3.3 测试 pod 挂载 nfs 是否成功 K8s 持久化存储 在 k8s…

[附源码]Nodejs计算机毕业设计基于框架的在线问答平台Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

[附源码]Python计算机毕业设计公租房管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

ASPICE详细介绍-1.什么是ASPICE?

什么是ASPICE&#xff1f; ASPICE全称是“Automotive Software Process Improvement and Capacity dEtermination”&#xff0c;即汽车软件过程改进及能力评定&#xff0c;简称A-SPICE或ASPICE。 属于过程模型&#xff0c;由过程和能力度两个维度构成&#xff0c;用于评价汽车…

DBeaver连接hive(详细图解)

文章目录DBeaver 简介使用DBeaver连接hive&#xff08;1&#xff09;配置Maven仓库&#xff08;2&#xff09;配置hive驱动&#xff08;3&#xff09;创建hive连接&#xff08;4&#xff09;连接测试DBeaver 简介 dbeaver是免费和开源&#xff08;GPL&#xff09;为开发人员和数…