剑指 Offer II 001. 整数除法
给定两个整数 a 和 b ,求它们的除法的商 a/b ,要求不得使用乘号 '*'、除号 '/' 以及求余符号 '%' 。
题解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 数组中重复的数据
标记为负数
/**
利用数组下标 对于遍历过的数字加上-号
[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. 找到所有数组中消失的数字
加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. 查找共用字符
利用字符作为下标
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. 上升下降字符串
题解
/**
* @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;
};