目录
- 常用算法理解
- 3. 数组中重复的数字
- 4. 二维数组中的查找
- 5. 替换空格
- 6. 从尾到头打印链表
- 7. 重建二叉树
- 9. 用两个栈实现队列
- 10-1. 斐波那契数列
- 10-2. 青蛙跳台阶问题
- 11. 旋转数组的最小数字
- 12. 矩阵中的路径(深度优先搜索)
- 13. 机器人的运动范围 (DFS)
- 14-1. 剪绳子 (动态规划)
- 14-2. 剪绳子 II (大数越界求余)
- 15. 二进制中1的个数
- 16. 数值的整数次方
- 17. 打印从1到最大的n位数
- 18. 删除链表的节点
- 24. 反转链表
- 25. 合并两个排序的链表
- 46. 把数字翻译成字符串 (动态规划)
- 57. 和为s的两个数字 (双指针)
- 备注
常用算法理解
- 深度优先搜索(DFS)
DFS 通过递归,先朝一个方向搜到底,再回溯至上个节点,沿另一个方向搜索,以此类推。
剪枝: 搜索中,遇到条件不符合的情况(边界),立即返回。
步骤: 1️⃣.考虑遍历路径2️⃣.考虑边界条件3️⃣.存储遍历状态 - 动态规划
整体问题的最优解依赖各个子问题的最优解(以小见大)
==》把全局问题化为局部问题
步骤: 1️⃣确定状态转移方程2️⃣确定边界条件3️⃣将边界条件赋予初值4️⃣实现状态转移得出最优解 - 贪心算法
在对问题求解时,总是做出当前看来最好的选择,也就是说它不从整体最优上加以考虑,而是仅在局部考虑最优解。 - 快速幂
二分思想的一种应用,降低时间复杂度。
通过循环 x = x^2,每次把幂从 n降至 n/2 ,直至为 0.
3. 数组中重复的数字
题目:
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
思路:
- 循环数组
- 排序后相邻间比较
- set去重
/**
* @param {number[]} nums
* @return {number}
*/
var findRepeatNumber = function(nums) {
if(nums.length==0) return false;
//1.循环比较(耗时) (1420 ms / 43.1 MB)
for(let i=0;i<nums.length;i++){
for(let j=i+1;j<nums.length;j++){
if(nums[i]==nums[j]){
return nums[i];
}
}
}
//2.排序后比较(优) (104 ms / 44.2 MB)
nums.sort();
for(let i=0;i<nums.length;i++){
if(nums[i]==nums[i+1]){
return nums[i];
}
}
//3.set 判断 size (100 ms / 45.9 MB)
let s=new Set();
let len=0;
for(let i=0;i<nums.length;i++){
s.add(nums[i]);
if(len==s.size){
return nums[i];
}else{
len=s.size;
}
}
//4. set判断 has (88 ms / 45.6 MB)
let s=new Set();
for(let i=0;i<nums.length;i++){
if(s.has(nums[i])){
return nums[i];
}else{
s.add(nums[i]);
}
}
return false;
};
4. 二维数组中的查找
题目:
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
示例:
现有矩阵 matrix 如下:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。给定 target = 20,返回 false。
思路:
- 暴力矩阵遍历
- 线性查找
- 二叉搜索树
/**
* @param {number[][]} matrix
* @param {number} target
* @return {boolean}
*/
var findNumberIn2DArray = function(matrix, target) {
//1. 矩阵遍历 (88 ms / 40.6 MB)
for(let i=0;i<matrix.length;i++){
for(let j=0;j<matrix[0].length;j++){
if(target==matrix[i][j]){
return true;
}
}
}
//2. (因为已经是顺序)线性查找 (104 ms / 40.7 MB )
for(let i=0;i<matrix.length;i++){
if(target<matrix[i][0]){
return false;
}
for(let j=0;j<matrix[0].length;j++){
if(target==matrix[i][j]){
return true;
}else if(target<matrix[i][j]){
continue;
}
}
}
//3. 二叉搜索树(优) (76 ms / 40.9 MB)
for(let i=0;i<matrix.length;i++){
for(let j=matrix[0].length;j>=0;j--){
if(target==matrix[i][j]){
return true;
}else if(target>matrix[i][j]){
continue;
}
}
}
return false;
};
5. 替换空格
题目:
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
思路:
- 转换成数组替换再合成字符串
- replace / replaceAll
/**
* @param {string} s
* @return {string}
*/
var replaceSpace = function(s) {
//1. 转换数组 (84 ms / 37.6 MB )
let arr=Array.from(s);
for(let i=0;i<arr.length;i++){
if(arr[i]==' '){
arr[i]="%20";
}
}
return arr.join('');
//2. 库函数 (92 ms / 37.5 MB )
return s.replaceAll(" ","%20");
};
6. 从尾到头打印链表
题目:
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
思路:
- 遍历链表,从数组头部插入(unshift)(88 ms / 39.7 MB)
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {number[]}
*/
var reversePrint = function(head) {
let arr=new Array();
let cur=head;
while(cur){
//结点为null时无法取值,所以判断当前节点是否存在
arr.unshift(cur.val);
cur=cur.next;
}
return arr;
};
7. 重建二叉树
题目:
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
思路:
划分左右子树,分别获取其前序遍历和中序遍历,然后递归生成树