序号为LeetCode的题序,语言选择的是JavaScript
https://leetcode-cn.com/problems/reverse-integer/
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
这题一拿到手,最先也是最容易想到的就是将数字传转换成字符串然后进行反转
数字 ——> 字符串 ——> 数组 ——> 反转 ——> 字符串 ——> 数字
注意分清楚正负号,还有题目的条件,即可得到答案
var reverse = function(x) {
let res = 0;
if (x >= 0) {
res = +String(x).split("").reverse().join("");
} else {
x = -x;
res = -String(x).split("").reverse().join("");
}
if(res > 2**31 - 1 || res < -(2**31)) return 0;
return res;
};
再想着用数学的方式来试试,不需要开辟新的空间来进行反转
整数除以10 余数为其个位数 商为去除个位数的剩余数字 (需要取整)
整体思路就是遍历(x / 10
商)数字x
,每次拿数字的个位(x % 10
余数),直到拿完。
每次遍历都将x
的个位 拼接到result
的新腾出的个位上(result = result * 10 + (x % 10);
)
/**
* @param {number} x
* @return {number}
*/
var reverse = function (x) {
let result = 0;
while (x) {
result = result * 10 + (x % 10);
if (result > 2 ** 31 - 1 || result < -(2 ** 31)) return 0;
x = ~~(x / 10);
}
return result;
};
~~
取整(舍去小数位)~
按位取反
对于整数相当于取反减一
~0 === -1
~1 === -2
~-1 === 0
~-2 === 1
对于小数相当于舍去小数位再取反减一
~0.3 === -1
~1.7 === -2
~-0.3 === -1
~-1.2 === 0
~-2.9 === 1
~~
按位取反再取反
对于整数还是自身
~~1 === 1
~~-1 === -1
~~0 === 0
对于小数,等于舍去小数位
相当于正数向下取整,负数向上取整
~~1.1 === 1
~~1.9 === 1
~~-1.1 === -1
~~-1.9 === -1
Math.floor()
向下取整Math.floor()
是向下取整
Math.floor(1.1) === 1
Math.floor(1.9) === 1
Math.floor(-1.1) === -2
Math.floor(-1.9) === -2
https://leetcode-cn.com/problems/roman-to-integer/
map.get(s[i])
)正常情况下 小的数在大的数的右边 直接累加
要先排除特殊情况 小的数在大的数的左边,那就给它前面加一个负号
/**
* @param {string} s
* @return {number}
*/
var romanToInt = function (s) {
let map = new Map();
map
.set("I", 1)
.set("V", 5)
.set("X", 10)
.set("L", 50)
.set("C", 100)
.set("D", 500)
.set("M", 1000);
let result = 0;
for (let i = 0; i < s.length; i++) {
let value = map.get(s[i]);
if (i < s.length - 1 && value < map.get(s[i + 1])) {
result -= value;
} else {
result += value;
}
}
return result;
};
switch
语句有限种确定情况,完全可以用switch
语句
/**
* @param {string} s
* @return {number}
*/
var romanToInt = function (s) {
let result = 0;
for (let i = 0; i < s.length; i++) {
let value = getValue(s[i]);
if (i < s.length - 1 && value < getValue(s[i + 1])) {
result -= value;
} else {
result += value;
}
}
return result;
};
function getValue(s) {
switch (s) {
case "I":
return 1;
case "V":
return 5;
case "X":
return 10;
case "L":
return 50;
case "C":
return 100;
case "D":
return 500;
case "M":
return 1000;
default:
return 0;
}
}
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即, x n x^n xn)。
/**
* @param {number} x
* @param {number} n
* @return {number}
*/
var myPow = function(x, n) {
let result = 1
if(n < 0){
x = parseFloat(1/x)
n = -n
}
while (n > 0) {
if ((n & 1) === 1) result *= x;
x *= x
n >>>= 1;
}
return result
};
也可以这样最后处理
var myPow = function(x, n) {
let result = 1
let flag = false
if(n < 0){
flag = true
n = -n
}
while (n > 0) {
if ((n & 1) === 1) result *= x
x *= x
n >>>= 1
}
if(flag){
result = parseFloat(1/result)
}
return result
};
https://leetcode-cn.com/problems/two-sum/
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
拿到题最容易想到的就是两层循环遍历,固定一个元素,查找另一个元素
i
遍历一遍数组;
j
从i+1
开始遍历剩余部分,看是否能找到等于 target-nums[i]
的元素, 找到返回下标
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function (nums, target) {
for (let i = 0; i < nums.length - 1; i++) {
for (let j = i + 1; j < nums.length; j++) {
if (nums[j] === target - nums[i]) {
return [i, j];
}
}
}
return [];
};
复习一下ES6的Map
map会维护插入时的顺序
// 定义空map
let map = new Map();
// 添加元素
map.set("key1","value1").set("key2", "value2");
// 查询元素
map.has("key1"); // true
map.get("key1"); // "value1"
map.size === 2;
构建映射【值:下标】
遍历nums构建map,之后只需在map中查找元素,而不需要每次都遍历剩余数组了
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
let map = new Map();
for(let i = 0; i < nums.length; i++){
let value = target - nums[i]
if(map.has(value)){
return [map.get(value), i]
}else {
// 找不到就插入到 map中
map.set(nums[i], i)
}
}
return [];
};
注意这里有一个坑,往map中存数据(set)操作要在判断语句之后!
因为不可以重复取两次自己,所以要在之前存入的元素中查找!!!
https://leetcode-cn.com/problems/container-with-most-water/
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。
在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
初始时,两个指针分别指向数组的两端,得到当前可以容纳的水的容量
每次移动一个指针,就是指向的值小的那个指针
这道题操作起来其实很简单,然而其中的重点是这种方法的【正确性】,我们在移动指针的时候抛弃了很多的解,但是这些解是可以抛弃的解,不会影响结果的解
将本题的搜索空间用矩阵表示出来就是这样的【白色区域】
如果遍历所有的解【所有小方块】,就需要O(N^2)的复杂度
通过本题的双指针来缩减搜索空间
双指针最先得到的解是右上方的解
假设左边的 0 号柱子较短。0 号柱子目前的水面高度已经到了上限。
由于 7 号柱子已经是离 0 号柱子最远的了,水的宽度也最大,如果换其他的柱子和 0 号柱子配对,水的宽度只会更小,高度也不会增加,容纳水的面积只会更小。
也就是说,0 号柱子和6,5,4,3,2,1号柱子的配对都可以排除掉了。
记录了 (0,7) 这组柱子的结果之后,就可以排除 0 号柱子了。
这相当于 i=0 的情况全部被排除。
对应于双指针解法的代码