文章目录
- 剑指 Offer 03. 数组中重复的数字
- 剑指 Offer 04. 二维数组中的查找
- 剑指 Offer 05. 替换空格
- 剑指 Offer 06. 从尾到头打印链表
- 剑指 Offer 09. 用两个栈实现队列
- 剑指 Offer 10- I. 斐波那契数列
- 剑指 Offer 11. 旋转数组的最小数字
- 剑指 Offer 17. 打印从 1 到最大的 n 位数
- 剑指 Offer 18. 删除链表的节点
- 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
- 剑指 Offer 22. 链表中倒数第 k 个节点
- 剑指 Offer 24. 反转链表
- 剑指 Offer 25. 合并两个排序的链表
- 剑指 Offer 27. 二叉树的镜像
- 剑指 Offer 28. 对称的二叉树
- 剑指 Offer 29. 顺时针打印矩阵
- 剑指 Offer 30. 包含 min 函数的栈
- 剑指 Offer 32 - I. 从上到下打印二叉树
- 剑指 Offer 32 - II. 从上到下打印二叉树 II
- 剑指 Offer 32 - III. 从上到下打印二叉树 III
- BFS 翻转二叉树(附加)
- 剑指 Offer 39. 数组中出现次数超过一半的数字
- [剑指 Offer 40\. 最小的k个数](https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/)
- 剑指 Offer 42. 连续子数组的最大和
- 剑指 Offer 45. 把数组排成最小的数
- 剑指 Offer 47. 礼物的最大价值
- 剑指 Offer 50. 第一个只出现一次的字符
- 剑指 Offer 52. 两个链表的第一个公共节点
- 剑指 Offer 53 - I. 在排序数组中查找数字 I
- [剑指 Offer 53 - II. 0~n-1中缺失的数字](https://leetcode-cn.com/problems/que-shi-de-shu-zi-lcof/)
- 剑指 Offer 54. 二叉搜索树的第 k 大节点
- 剑指 Offer 55 - I. 二叉树的深度
- 剑指 Offer 56 - I. 数组中数字出现的次数
- 剑指 Offer 56 - II. 数组中数字出现的次数 II
- 剑指 Offer 57. 和为 s 的两个数字
- [剑指 Offer 57 - II. 和为s的连续正数序列](https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/)
- 剑指 Offer 58 - I. 翻转单词顺序
- 剑指 Offer 58 - II. 左旋转字符串
- 剑指 Offer 59 - I. 滑动窗口的最大值
- 剑指 Offer 60. n个骰子的点数
- [剑指 Offer 61\. 扑克牌中的顺子](https://leetcode-cn.com/problems/bu-ke-pai-zhong-de-shun-zi-lcof/)
- [剑指 Offer 62\. 圆圈中最后剩下的数字](https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/)
- 剑指 Offer 66. 构建乘积数组
题目链接:
题目描述:
解题思路:
剑指 Offer 03. 数组中重复的数字
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xzktv1/
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
- 思路 1 使用库函数申请额外空间
使用 HashSet 来进行处理,因为 HashSet 本身不允许出现重复元素,所以当添加元素失败或已经包含该数字时,则表示出现了重复元素,将其返回即可。
时间复杂度:O(n),空间复杂度:O(n)
var findRepeatNumber = function(nums) {
var numsSet = new Set();
for(var num of nums){
if(numsSet.has(num)){
return num;
}else{
numsSet.add(num)
}
}
return false
};
- 思路 2 数组本身做哈希表,达到了节省空间的目的
时间复杂度:O(n),空间复杂度:O(1)
var findRepeatNumber = function(nums) {
for(var i = 0; i<nums.length ; i++){
while(nums[i] != i){
if(nums[i] == nums[nums[i]]){
return nums[i]
}
var tmp = nums[i];
nums[i] =nums[tmp];
nums[tmp] = tmp;
}
}
return false
};
剑指 Offer 04. 二维数组中的查找
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xz2hh7/
var findNumberIn2DArray = function(matrix, target) {
let col = matrix.length;
if(!col) return false
let row = matrix[0].length;
let i=col-1, j=0;
while(i>=0 && j<row){
if(matrix[i][j] == target){
return true;
}else if(matrix[i][j] > target){
i--;
}else{
j++;
}
}
return false;
};
剑指 Offer 05. 替换空格
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xz2cf5/
var replaceSpace = function(s) {
return s.split(' ').join('%20')
};
//数组
var replaceSpace = function(s) {
var res ='';
for(i = 0; i<s.length; i++){
if(s[i] == " "){
res += '%20';
} else{
res += s[i]
}
}
return res
};
剑指 Offer 06. 从尾到头打印链表
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xs92sh/
- 方法一:reverse()
var reversePrint = function(head) {
var stack = [];
while(head != null){
stack.push(head.val);
head = head.next
}
return stack.reverse()
};
- 方法二:栈(先进后出,push+pop)
var reversePrint = function(head) {
var stack = [];
while(head != null){
stack.push(head.val);
head = head.next;
}
var res = [];
const len = stack.length; //需要初始stack的长度
for(var i = 0; i< len; i++){
res.push(stack.pop()); //stack长度会不断变化
}
return res;
};
剑指 Offer 09. 用两个栈实现队列
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xz8cid/
var CQueue = function() {
this.stack1=[];
this.stack2 = [];
};
/**
* @param {number} value
* @return {void}
*/
CQueue.prototype.appendTail = function(value) {
this.stack1.push(value)
};
/**
* @return {number}
*/
CQueue.prototype.deleteHead = function() {
if(this.stack2.length==0){
while(this.stack1.length != 0){
this.stack2.push(this.stack1.pop())
}
}
if(this.stack2.length==0){
return -1
}else {
return this.stack2.pop()
}
};
剑指 Offer 10- I. 斐波那契数列
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xslxpr/
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
var fib = function(n) {
let f0 = 0, f1 = 1, fn;
if(n<2){
return n
}
for(let i = 2; i<=n ;i++){
fn = (f0 + f1) % 1000000007;
f0 = f1;
f1 = fn;
}
return fn
};
剑指 Offer 11. 旋转数组的最小数字
- 题目链接:https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/
- 解题思路:https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/solution/mian-shi-ti-11-xuan-zhuan-shu-zu-de-zui-xiao-shu-3/
- 题目描述:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
输入:[3,4,5,1,2]
输出:1
var minArray = function(numbers) {
let i=0,j=numbers.length-1;
while(i<j){
let m=parseInt((i+j)/2)
if(numbers[m]<numbers[j]){
j=m;
}else if(numbers[m]==numbers[j]){
j--;
}else{
i=m+1;
}
}
return numbers[i]
};
剑指 Offer 17. 打印从 1 到最大的 n 位数
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xzvgc2/
var printNumbers = function(n) {
if(n==0){
return false;
}
let all = Math.pow(10,n);
// let all=1
// for(var i=0;i<n;i++){
// all = 10*all
// }
let arr = [];
for(var i=1;i<all;i++){
arr.push(i)
}
return arr;
};
剑指 Offer 18. 删除链表的节点
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xz4mp2/
时间复杂度:O(n),空间复杂度:O(1)
var deleteNode = function(head, val) {
if(head == null){
return null;
}
if(head.val == val){
return head.next;
}
var left = head;
var cur = left.next
while(cur.val != val && cur.next!= null){
left=cur;
cur=cur.next;
}
if(cur != null){
left.next=cur.next
}
return head
};
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
var exchange = function(nums) {
var a = [];
var b = [];
for(var i=0;i<nums.length;i++){
if (nums[i]%2==1){
a.push(nums[i])
}else{
b.push(nums[i])
}
}
return a.concat(b)
};
双指针
var exchange = function(nums) {
let right = nums.length-1;
let left = 0;
let tmp;
while(left<right){
if(left<right &&(nums[right]%2) == 0 ){
right--;
}
if(left<right &&(nums[left]%2) == 1){
left++;
}
tmp = nums[left]
nums[left] = nums[right]
nums[right] = tmp
}
return nums
};
剑指 Offer 22. 链表中倒数第 k 个节点
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xzy5ei/
时间复杂度:O(n),空间复杂度:O(1)
var getKthFromEnd = function(head, k) {
var cur = head;
var post= head;
for(var i=0; i<k; i++){
cur = cur.next;
}
while(cur!=null){
cur = cur.next;
post = post.next
}
return post
};
剑指 Offer 24. 反转链表
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xzccxg/
时间复杂度:O(n),空间复杂度:O(1)
var reverseList = function(head) {
var cur = null;
var pre = head;
while(pre!=null){
var tmp = pre.next;
pre.next = cur;
cur = pre;
pre = tmp;
}
return cur
};
剑指 Offer 25. 合并两个排序的链表
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xzjkjj/
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。O(m+n)
var mergeTwoLists = function(l1, l2) {
if(l2==null){
return l1
}
if(l1==null){
return l2
}
if(l1.val>l2.val){
l2.next = mergeTwoLists(l1,l2.next);
return l2
}else{
l1.next = mergeTwoLists(l2,l1.next);
return l1
}
};
剑指 Offer 27. 二叉树的镜像
- 时间复杂度:O(n),空间复杂度:O(n)
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xsepg3/
例如输入:
4
2 7
1 3 6 9
镜像输出:
4
7 2
9 6 3 1
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
var mirrorTree = function(root) {
let res = null;
if(root != null){
res =new TreeNode(root.val);
res.left = mirrorTree(root.right);
res.right = mirrorTree(root.left);
}
return res
};
剑指 Offer 28. 对称的二叉树
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xsrxq1/
- 时间复杂度:O(n)
var isSymmetric = function(root) {
if(root==null){
return true;
}
return dfs(root.left,root.right)
};
var dfs = function(t1, t2){
if(t1==null && t2==null) {return true}
if(t1==null|| t2==null) {return false}
if(t1.val != t2.val){return false}
return dfs(t1.left,t2.right) && dfs(t1.right,t2.left)
}
剑指 Offer 29. 顺时针打印矩阵
题目描述:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
https://leetcode-cn.com/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
题解:https://leetcode-cn.com/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/solution/shou-hui-tu-jie-liang-chong-bian-li-de-ce-lue-na-c/
循环的条件是 top <= bottom && left <= right
。
每遍历完一条边,下一条边遍历的起点被“挤占”,所以要更新相应的边界。
因为要在循环过程中更新边界,所以可能出现:循环的条件在中途不再满足,即 top > bottom || left > right
,其中一对边界彼此交错了。
这代表此时所有项都遍历完了,如果不马上 break,就会重复遍历,造成元素重复地进入结果数组。
var spiralOrder = function(matrix) {
if(matrix.length==0){
return []
}
const res = []
let bottom = matrix.length-1
let right =matrix[0].length-1;
let top=0,left=0;
while(top<=bottom && left<=right){
for(let i=left;i<=right;i++) res.push(matrix[top][i])
top++;
for(let i=top;i<=bottom;i++) res.push(matrix[i][right])
right--;
if (top > bottom || left > right) break;
for(let i=right;i>=left;i--) res.push(matrix[bottom][i])
bottom--;
for(let i=bottom;i>=top;i--) res.push(matrix[i][left])
left++
}
return res;
};
剑指 Offer 30. 包含 min 函数的栈
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xzqg03/
解题思路:https://leetcode-cn.com/problems/bao-han-minhan-shu-de-zhan-lcof/solution/mian-shi-ti-30-bao-han-minhan-shu-de-zhan-fu-zhu-z/
/**
* initialize your data structure here.
*/
var MinStack = function() {
this.stack1 = [];
this.stack2 = [];
};
/**
* @param {number} x
* @return {void}
*/
MinStack.prototype.push = function(x) {
this.stack1.push(x);
if(this.stack2.length == 0 || this.stack2[this.stack2.length - 1] >= x) {
this.stack2.push(x);
}
};
/**
* @return {void}
*/
MinStack.prototype.pop = function() {
if(this.stack1.pop() == this.stack2[this.stack2.length - 1]) {
this.stack2.pop();
}
};
/**
* @return {number}
*/
MinStack.prototype.top = function() {
return this.stack1[this.stack1.length - 1];
};
/**
* @return {number}
*/
MinStack.prototype.min = function() {
return this.stack2[this.stack2.length - 1];
};
/**
* Your MinStack object will be instantiated and called as such:
* var obj = new MinStack()
* obj.push(x)
* obj.pop()
* var param_3 = obj.top()
* var param_4 = obj.min()
*/
剑指 Offer 32 - I. 从上到下打印二叉树
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xsnu0i/
例如:
给定二叉树: [3,9,20,null,null,15,7],
返回:[3,9,20,15,7]
解题思路:BFS
var levelOrder = function(root) {
if(root == null){
return [];
}
let queue = [root];
let res = [];
while(queue.length != 0){
let node = queue.shift();
res.push(node.val);
if(node.left){
queue.push(node.left);
}
if(node.right){
queue.push(node.right);
}
}
return res
};
剑指 Offer 32 - II. 从上到下打印二叉树 II
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xswwvg/
从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。
给定二叉树: [3,9,20,null,null,15,7],
返回其层次遍历结果:[[3],[9,20], [15,7]]
解题思路:BFS
时间复杂度:O(n),空间复杂度:O(n)
1、判断 root 是否为 null,如果为 null 则直接返回空数组
2、初始化队列,并将初始的 root 节点加入队列之中
3、当队列不为空时不断广度遍历二叉树,遍历时依次从队列中取出节点,取出后如果该节点存在左节点 则将左节点放入队列中,如果该节点存在右节点则将右节点放入队列中
4、在遍历过程中存储结果,最后将结果按照要求的格式返回
var levelOrder = function(root) {
if(root == null){
return [];
}
let queue = [root];
let res = [];
while(queue.length != 0){
let level = [];
let len = queue.length;
for(let i = 0; i < len; i++){
let node = queue.shift(); //shift() 方法删除数组第一个元素
level.push(node.val);
if(node.left){
queue.push(node.left);
}
if(node.right){
queue.push(node.right);
}
}
res.push(level)
}
return res
};
剑指 Offer 32 - III. 从上到下打印二叉树 III
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xs0paj/
请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
例如:
给定二叉树: [3,9,20,null,null,15,7],
返回其层次遍历结果:[[3],[20,9], [15,7]]
解题思路:BFS
var levelOrder = function(root) {
if(root == null){
return [];
}
let queue = [root];
let res = [];
let flag = 1;
while(queue.length != 0){
let level = [];
let len = queue.length;
for(let i = 0; i < len; i++){
let node = queue.shift();
if(flag==1){
level.push(node.val);
}else{
level.unshift(node.val);
};
if(node.left){
queue.push(node.left);
}
if(node.right){
queue.push(node.right);
}
}
flag = -flag;
res.push(level)
}
return res
};
BFS 翻转二叉树(附加)
var mirrorTree = function(root) {
if(root == null){
return []
}
let res = [];
let queue = [root];
while(queue.length != 0 ){
let node = queue.shift();
res.push(node.val);
if(node.right){
queue.push(node.right)
}
if(node.left){
queue.push(node.left)
}
}
return res
};
剑指 Offer 39. 数组中出现次数超过一半的数字
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xz7dgg/
方法一:数组排序:首先将 nums 排序,由于该数字超过数组长度的一半,所以数组的中间元素就是答案,时间复杂度为 O(nlogn)
var majorityElement = function(nums) {
nums.sort((a,b) => a-b)
return nums[parseInt(nums.length / 2 )]
}
方法一:哈希计数:遍历 nums 数组,将数字存在 HashMap 中,统计数字出现次数,统计完成后再遍历一次 HashMap,找到超过一半计数的数字,时间复杂度为 O(n)
摩尔投票:遍历 nums 数组,使用 count 进行计数,记录当前出现的数字为 cur,如果遍历到的 num 与 cur 相等,则 count 自增,否则自减,当其减为 0 时则将 cur 修改为当前遍历的 num,通过增减抵消的方式,最终达到剩下的数字是结果的效果,时间复杂度为 O(n)
- 摩尔投票是最优解法,时间复杂度:O(n),空间复杂度:O(1)
var majorityElement = function(nums) {
let cur ,count=0;
for(let i = 0; i<nums.length; i++){
if(count == 0){
cur = nums[i];
}
if(nums[i] == cur){
count++;
}else{
count--
}
}
return cur
}
剑指 Offer 40. 最小的k个数
- 题目:输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
解法 1: 直接排序
思路和算法:对原数组从小到大排序后取出前 k个数即可。
var getLeastNumbers = function(arr, k) {
arr.sort((a,b)=>a-b)
var min=[]
for(var i=0;i<k;i++){
min.push(arr[i]);
}
return min
};
解法 2: 最大堆
解法 3: 基于快速排序的 partition
剑指 Offer 42. 连续子数组的最大和
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xsiyed/
输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)。
var maxSubArray = function(nums) {
let res = nums[0]
for(let i = 1; i<nums.length ;i++){
if(nums[i-1]>0){
nums[i] += nums[i-1]
}else{
nums[i] = nums[i]
}
res = Math.max(res,nums[i])
}
return res
};
剑指 Offer 45. 把数组排成最小的数
- 题目链接:https://leetcode-cn.com/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof/
- 题目描述:输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
- 解题思路:排序或者内置排序函数
排序判断规则: 设nums
任意两数字的字符串格式 x 和 y ,则
若拼接字符串x + y > y + x
,则m > n
;
反之,若x + y < y + x
,则n < m
;
var minNumber = function(nums) {
nums.sort((a,b)=>(" "+a+b)-(" "+b+a))
return nums.join("")
};
剑指 Offer 47. 礼物的最大价值
- 题目链接:https://leetcode-cn.com/leetbook/read/illustrate-lcof/xstkx3/
- 题目描述:在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
- 解题思路:动态规划
var maxValue = function(grid) {
let col = grid.length;
let row = grid[0].length;
for(let i = 0; i<col ;i++){
for(let j = 0; j<row ; j++){
if(i >= 1 && j >= 1){
grid[i][j] += Math.max(grid[i-1][j],grid[i][j-1]);
}else if(i >= 1){
grid[i][j] += grid[i-1][j];
}else if(j >= 1){
grid[i][j] += grid[i][j-1];
}
}
}
return grid[col-1][row-1];
};
var maxValue = function(grid) {
let col = grid.length;
let row = grid[0].length;
for(let i = 0; i<col ;i++){
for(let j = 0; j<row ; j++){
if(i == 0 && j==0){
continue;
}else if(i == 0){
grid[i][j] += grid[i][j-1];
}else if(j==0){
grid[i][j] += grid[i-1][j];
}else {
grid[i][j] += Math.max(grid[i-1][j],grid[i][j-1]);
}
}
}
return grid[col-1][row-1];
};
剑指 Offer 50. 第一个只出现一次的字符
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xzzd25/
- 在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
示例: s = "abaccdeff" ,返回 "b";
示例: s = "" , 返回 " "
- 思路: hash,首先遍历字符串将每个字符串映射到固定的位置,并且该位置存储字符串的出现次数,然后再遍历一次字符串,找到第一个只出现一次的字符
时间复杂度:O(n),空间复杂度:O(1)
var firstUniqChar = function(s) {
var maps = new Map();
for(var num of s){ // for in 遍时取得值的key和index,for of 遍时取得值的value
maps.set(num, maps.has(num))
}
for(var num of s){
if(maps.get(num)==0){
return num;
}
}
return " "
};
剑指 Offer 52. 两个链表的第一个公共节点
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xshucr/
使用两个指针 node1,node2 分别指向两个链表 headA,headB 的头结点,然后同时分别逐结点遍历,
当 node1 到达链表 headA 的末尾时,重新定位到链表 headB 的头结点;
当 node2 到达链表 headB 的末尾时,重新定位到链表 headA 的头结点。
这样,当它们相遇时,所指向的结点就是第一个公共结点。
- 时间复杂度:O(M+N)。
- 空间复杂度:O(1)O(1)。
//(双指针法)
var getIntersectionNode = function(headA, headB) {
let curA = headA;
let curB = headB;
while (curA != curB) {
curA = curA != null ? curA.next : headB;
curB = curB != null ? curB.next : headA;
}
return curA;
};
剑指 Offer 53 - I. 在排序数组中查找数字 I
题目链接:https://leetcode-cn.com/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/
解题思路:二分法
题目描述:统计一个数字在排序数组中出现的次数。
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
var search = function(nums, target) {
if(nums.length==0) return false;
var left=0,right=nums.length-1
var count=0
while(left<=right){
let mid = parseInt((left+right)/2)
if(nums[mid]<target){
left=mid+1
}else if(nums[mid]>target){
right=mid-1
}else{
var count=1;
let low=mid-1;
let high=mid+1;
while(nums[low]===target){
low--
count++
}
while(nums[high]===target){
high++
count++
}
return count
}
}
return 0
};
剑指 Offer 53 - II. 0~n-1中缺失的数字
解法 1: 遍历
var missingNumber = function(nums) {
if(nums[i]==0){
return 1
}
for(var i=0;i<nums.length;i++){
if(nums[i]!=i){
return i
}
}
return nums.length
};
解法 2: 二分查找(有序数组都应该想到二分查找)
var missingNumber = function(nums) {
let i = 0;
let j = nums.length-1;
while(i <= j){
let mid =parseInt((i + j) / 2)
if(nums[mid] == mid){
i = mid + 1;
}else{
j = mid - 1
}
}
return i
};
剑指 Offer 54. 二叉搜索树的第 k 大节点
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xspy85/
- 时间复杂度:O(n),空间复杂度:O(1)
- 二叉搜索树:根节点的值大于其左子树中任意一个节点的值,小于其右节点中任意一节点的值,这一规则适用于二叉查找树中的每一个节点。
- 二叉搜索树的【中序遍历】为 【递增序列】,易得二叉搜索树的 【中序遍历倒序】 为 【递减序列】 。
因此,求 “二叉搜索树第 k大的节点” 可转化为求 “此树的【中序遍历倒序】的第 k 个节点”。 中序遍历 为 “左、根、右” 顺序,倒序就是“右、根、左” 。
时间复杂度:O(n),空间复杂度:O(1)
var nums;
var res;
var kthLargest = function(root, k) {
nums = k
dfs(root);
return res;
};
var dfs = function(root){
if(root == null){
return;
}
dfs(root.right);
if(nums == 0){
return
}
nums --;
if(nums==0){
res = root.val
}
dfs(root.left)
}
剑指 Offer 55 - I. 二叉树的深度
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xsaki2/
解题思路:
-
后序遍历(DFS)
-
树的后序遍历 / 深度优先搜索往往利用 递归 或 栈 实现,本文使用递归实现。
-
关键点: 此树的深度和其左(右)子树的深度之间的关系。显然,此树的深度 等于 左子树的深度 与 右子树的深度 中的 最大值 +1 。
-
时间复杂度:O(n),空间复杂度:O(1)
var maxDepth = function(root) {
if(root == null){
return 0
}
return Math.max(maxDepth(root.left),maxDepth(root.right))+1
};
剑指 Offer 56 - I. 数组中数字出现的次数
- 题目:一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
- 思路:(和剑指 Offer 50类似)
var singleNumbers = function(nums) {
var map = new Map()
var res =[]
for(let i of nums){
map.set(i,map.has(i))
}
for(let key of nums){
if(map.get(key)==0)
res.push(key);
}
return res;
}
剑指 Offer 56 - II. 数组中数字出现的次数 II
- 题目:在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
输入:nums = [9,1,7,9,7,9,7]
输出:1
- 思路:(和剑指 Offer 50类似)
var singleNumbers = function(nums) {
var map = new Map()
var res =[]
for(let i of nums){
map.set(i,map.has(i))
}
for(let key of nums){
if(map.get(key)==0)
res.push(key);
}
return res;
}
剑指 Offer 57. 和为 s 的两个数字
https://leetcode-cn.com/leetbook/read/illustrate-lcof/xzimqj/
- 输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。
- 思路:有序数组,双指针
var twoSum = function(nums, target) {
var len = nums.length;
var left = 0;
var right = len-1;
var arr = []
for(var i = 0; i<len ;i++){
if(nums[left]+nums[right] == target){
// arr.push(nums[left]);
// arr.push(nums[right])
return [nums[left],nums[right]]
};
if(nums[left]+nums[right] > target){
right--
}
if(nums[left]+nums[right] < target){
left++
}
}
};
剑指 Offer 57 - II. 和为s的连续正数序列
-
题目描述:输入一个正整数
target
,输出所有和为target
的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例:输入:target = 9;输出:[[2,3,4],[4,5]]
方法:滑动窗口
var findContinuousSequence = function(target) {
var i=1;
var j=1;
var sum = 0;
var res =[];
while(i<=parseInt(target/2)){
if (sum<target){
sum+=j;
j++;
}else if(sum>target){
sum -=i;
i++;
}else{
let arr =[];
for(let k=i;k<j;k++){
arr.push(k);
}
res.push(arr)
sum -=i;
i++;
}
}
return res;
};
剑指 Offer 58 - I. 翻转单词顺序
var reverseWords = function(s) {
let arr =[];
let tmp=s.split(' ')
for(var i=0;i<tmp.length;i++){
if(tmp[tmp.length-i-1]!=""){
arr.push(tmp[tmp.length-i-1])
}
}
return arr.join(" ");
};
剑指 Offer 58 - II. 左旋转字符串
- 题目链接:https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/
- 题目描述:字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
输入: s = "abcdefg", k = 2
输出: "cdefgab"
- 解题思路:字符串切分
var reverseLeftWords = function(s, n) {
let str1 = s.split("").splice(0,n)
let str2 = s.split("").splice(n,s.length)
return str2.concat(str1).join("")
};
剑指 Offer 59 - I. 滑动窗口的最大值
题目链接:https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/
解题思路:https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/solution/mian-shi-ti-59-i-hua-dong-chuang-kou-de-zui-da-1-6/
题目描述:给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
var maxSlidingWindow = function(nums, k) {
if(nums.length==0||k==0) {
return [];
}
let left =0,arr=[];
while(left<=nums.length-k){
let max=nums[left]
for(let i=left; i<k+left; i++){
if(nums[i]> max){
max=nums[i]
}
}
arr.push(max)
left++
}
return arr;
};
剑指 Offer 60. n个骰子的点数
题目链接:https://leetcode-cn.com/problems/nge-tou-zi-de-dian-shu-lcof/
题目描述:把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。
你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。
输入: 1
输出: [0.16667,0.16667,0.16667,0.16667,0.16667,0.16667]
解题思路:https://leetcode-cn.com/problems/nge-tou-zi-de-dian-shu-lcof/solution/dong-tai-gui-hua-by-mayness/
通过动态规划来解决,已知若是1个骰子,则6面出现的概率都是一样的,即1/6
若是两个骰子,则可以在原来1个骰子的基础上进行概率计算,已知两个骰子的排列为
1+1
1+2 2+1
1+3 2+2 3+1
1+4 2+3 3+2 4+1
1+5 2+4 3+3 4+2 5+1
1+6 2+5 3+4 4+3 5+2 6+1
2+6 3+5 4+4 5+3 6+2
3+6 4+5 5+4 6+3
4+6 5+5 6+4
5+6 6+5
6+6
这里将上面的单个排列看做是sum = x + y
,x
为一个骰子【也可以理解为新的一个】甩出来的点数,y
为前几个骰子甩出来的和,这里由于总的骰子数为2,因此前几个骰子实际上就是上一个骰子。
其计算公式为dp[ sum ] = dp[ sum ] + dp[ y ] * 1/6
。由于x
只能甩出1~6
个数,因此概率肯定是1/6
,因此需要匹配的dp[ y ]
需要乘上1/6
。由此不断叠加得到n个骰子甩出来的概率。
//动态规划
var twoSum = function(n) {
let dp = [ 1/6, 1/6, 1/6, 1/6, 1/6, 1/6 ];
for(var i=2;i<=n;i++){
var tem=[]
for(var j=1;j<=6;j++){
for(var k=0;k<dp.length;k++){
let sum=j+k-1;
tem[sum]=(tem[sum]||0)+dp[k]*1/6;
}
}
dp=tem
}
return dp
};
剑指 Offer 61. 扑克牌中的顺子
- 题目:从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。
- 方法:排序 + 遍历
- 思路:最大值-最小值<5,且没有重复的数字。
var isStraight = function(nums) {
nums.sort((a,b) => a-b);
var len = nums.length;
var joker = 0;//判断0的个数
for(var i = 0; i<len ;i++){
if(nums[i] === 0){
joker++
}else if(nums[i] == nums[i+1]){
return false
}
}
return (nums[len-1]-nums[joker] < 5) ? true :false // 最大值-最小值 <5
};
剑指 Offer 62. 圆圈中最后剩下的数字
- 题目:0,1,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。 - 题解:https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/solution/huan-ge-jiao-du-ju-li-jie-jue-yue-se-fu-huan-by-as/
1、递归
递推公式:f(N,M) = ( f(N−1,M) + M ) % N
var lastRemaining = function(n, m) {
if(n==1){
return 0;
}
var res = lastRemaining(n-1,m)
return (res+m)%n
};
2、迭代实现
时间复杂度:O(n),需要求解的函数值有 n 个。
空间复杂度:O(1),只使用常数个变量。
var lastRemaining = function(n, m) {
if (n === 1) {
return 0;
}
var res = 0
for(var i=2;i<=n;i++){
res = (res+m)%i;
}
return res
};
剑指 Offer 66. 构建乘积数组
题目链接:https://leetcode-cn.com/problems/gou-jian-cheng-ji-shu-zu-lcof/
解题思路:https://leetcode-cn.com/problems/gou-jian-cheng-ji-shu-zu-lcof/solution/mian-shi-ti-66-gou-jian-cheng-ji-shu-zu-biao-ge-fe/
题目描述:
给定一个数组A[0,1,…,n-1]
,请构建一个数组 B[0,1,…,n-1]
,其中 B 中的元素 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]
。不能使用除法。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/gou-jian-cheng-ji-shu-zu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
输入: [1,2,3,4,5]
输出: [120,60,40,30,24]
var constructArr = function(a) {
var b=[];
var tmp=1;
for(var i=1;i<a.length;i++){
b[0]=1
b[i]=b[i-1] * a[i-1];
}
for(var i=a.length-2; i>=0;i--){
tmp = tmp * a[i+1];
b[i] *= tmp
}
return b;
};