leetcode刷题记录

135 阅读2分钟

剑指 Offer II 001. 整数除法

给定两个整数 a 和 b ,求它们的除法的商 a/b ,要求不得使用乘号 '*'、除号 '/' 以及求余符号 '%' 。

截屏2022-03-23 下午5.32.09.png

题解1

用减法代替除法。

a = 24, b = 7;

a  - b = a
24 - 7 = 17;
17 - 7 = 10;
10 - 7 = 3;
function division(a, b) {
    let sign = 1;
    if ((a > 0 && b < 0) || (a < 0 && b > 0)) sign = -1;
    let res = 0;
    a = Math.abs(a);
    b = Math.abs(b);
    while (a >= b) {
        a -= b;
        res++;
    }
    return sign > 0 ? res : -res;
}
  • 优化代码

异或运算

符号: ^

写法:数字1 ^ 数字2

计算规则:将数字 1 和数字 2 的二进制按位比较,不同为 1,相同为 0;

记忆方式:异1同0。

// 0
0000 0000 0000 0000 0000 0000 0000 0000
// 1
0000 0000 0000 0000 0000 0000 0000 0001
// 0 ^ 1 = 1
0000 0000 0000 0000 0000 0000 0000 0001

// 0
0000 0000 0000 0000 0000 0000 0000 0000
// 0
0000 0000 0000 0000 0000 0000 0000 0000
// 0 ^ 0 = 0
0000 0000 0000 0000 0000 0000 0000 0000

// 1
0000 0000 0000 0000 0000 0000 0000 0001
// 1
0000 0000 0000 0000 0000 0000 0000 0001
// 1 ^ 1 = 0
0000 0000 0000 0000 0000 0000 0000 0000

有上面理论可知,if ((a > 0 && b < 0) || (a < 0 && b > 0)),可以优化为(a > 0) ^ (b > 0): -1 : 1;

function division(a, b) {
    let sign = (a > 0) ^ (b > 0) ? -1 : 1
    let res = 0;
    a = Math.abs(a);
    b = Math.abs(b);
    while (a >= b) {
        a -= b;
        res++;
    }
    return sign > 0 ? res : -res;
}

左位移

左位移: <<

写法: 数字1 << 数字2

将数字2 的二进制(除符号位,31位),左移动数字2的次数

结果: (数字1) * 2ˆ(数字2)

console.log(2 << 3); // 2 * 2ˆ3 = 16

var divide = function(a, b) {
    const INT_MIN = -Math.pow(2, 31)
    const INT_MAX = Math.pow(2, 31) - 1

    if (a == INT_MIN && b == -1) return INT_MAX

    let res = 0

    // 处理边界,防止转正数溢出
    // 除数绝对值最大,结果必为 0 或 1
    if (b == INT_MIN) {
        return a == b? 1 : 0;
    }

    // 被除数先减去一个除数
    if (a == INT_MIN) {
        a -= -Math.abs(b);
        res += 1;
    }

    const sign = (a > 0) ^ (b > 0) ? -1 : 1
    a = Math.abs(a)
    b = Math.abs(b)

    for (let x = 31; x >= 0; x--) {
        if ((a >>> x) - b >= 0) {
            a = a - (b << x)
            // 代码优化:这里控制 res 大于等于 INT_MAX
            if (res > INT_MAX - (1 << x)) {
                return INT_MIN;
            }
            res = res + (1 << x)
        }
    }
    if (res == -2147483648) return -2147483648
    // bug 修复:因为不能使用乘号,所以将乘号换成三目运算符
    return sign == 1 ? res : -res
};

数组元素作为下标

该方法适用于arr[i]的取值范围

onst arr = [1, 2, 1, 4, 3, 2, 1, 4, 5, 6, 6, 6];

/**
 * 统计数组中每个元素出现的次数
 * @param arr arr[i] 取值范围较小
 * @returns 
 */
function getTargetCount(arr: number[]): number[] {
    const resArr = new Array(6).fill(0);
    for (const item of arr) {
        const index = item - 1;
        resArr[index]++;
    }
    return resArr;
}

console.log(getTargetCount(arr));
// [ 3, 2, 1, 2, 1, 3 ]

442 数组中重复的数据

截屏2022-04-09 下午11.16.39.png

标记为负数

/**
    利用数组下标 对于遍历过的数字加上-号

    [4,3,2,7,8,2,3,1]

    
    [4,-3,-2,-7,8,2,-3,-1]
 */ 
var findDuplicates = function(nums) {
    const resArr = [];
    for(let i = 0; i < nums.length; i++){
        const index = Math.abs(nums[i]) - 1;
        if(nums[index] > 0){
            nums[index] = -nums[index];
        } else {
            resArr.push(Math.abs(nums[i]));
        }
    }
    return resArr;
};

加n

var findDuplicates = function(nums) {
  const length = nums.length;
  const resArr = [];
  for(let i = 0; i < length; i++){
      const index = (nums[i] - 1) % length;
      nums[index] += length;
  }
  for(let i = 0; i < length; i++){
      if(nums[i] > 2 * length) resArr.push(i+1)
  } 
  return resArr;
};

448. 找到所有数组中消失的数字

截屏2022-04-09 下午11.59.53.png

加n

var findDisappearedNumbers = function(nums) {
    const n = nums.length;
    const resArr = [];
    for(let i = 0; i < n; i++){
        const index = (nums[i] - 1) % n;
        nums[index] += n;
    }
    for(let i = 0; i < n; i++){
        if(nums[i] <= n) resArr.push(i+1);
    }
    return resArr;
};

1002. 查找共用字符

截屏2022-04-10 下午9.00.08.png

利用字符作为下标

var commonChars = function(words) {
    // 统计字符串数组第一个字符串,每个字符出现的次数,
    // 同时该数组也做为字符出现次数最小的数组
    const countArr = new Array(26).fill(0);
    for(let i = 0; i < words[0].length; i++){
        const index = words[0][i].charCodeAt() - 'a'.charCodeAt();
        countArr[index]++;
    }
    // 遍历字符串数组剩下的字符串
    for(let i = 1; i < words.length; i++){
        const freqArr = new Array(26).fill(0);
        for(let j = 0; j < words[i].length; j++){
            const index = words[i][j].charCodeAt() - 97;
            freqArr[index]++;
        }
        // 比较记录字符次数的数组,获取字符出现最小的次数
        for(let i = 0; i < 26; i++){
            countArr[i] = Math.min(countArr[i], freqArr[i]);
        }
    }
    const resArr = [];
    for(let i = 0; i < 26; i++){
        // 次数大于1
        while(countArr[i] > 0){
            resArr.push(String.fromCharCode(97 + i));
            countArr[i]--;
        }
    }
    return resArr;
};

1370. 上升下降字符串

截屏2022-04-10 下午9.07.50.png

题解

/**
 * @param {string} s 由小写字母组成
 * @return {string}
 */
var sortString = function (s) {
    const charCountArr = new Array(26).fill(0);
    for (let i = 0; i < s.length; i++) {
        const index = s[i].charCodeAt() - 97;
        charCountArr[index]++;
    }
    let resStr = '';
    // 结果字符串长度小于输入字符串就要一直循环
    while(resStr.length < s.length){
        // 上升
        for(let i = 0; i < 26; i++){
            if(charCountArr[i] > 0){
                resStr += String.fromCharCode(i + 97);
                charCountArr[i]--;
            }
        }
        // 下降
        for(let i = 25; i >= 0; i--){
            if(charCountArr[i] > 0){
                resStr += String.fromCharCode(i + 97);
                charCountArr[i]--;
            }
        }
    }
    return resStr;
};