目的
为提升自身编码能力,熟悉数据结构和算法,从2023年3月份开始,每周刷三题,在此盖楼~
节奏
先刷完LeetCode的剑指Offer,个人主页:leetcode.cn/u/132607210…
盖楼
1.用两个栈实现队列
日期:2023-2-26
链接:点击此处
解题思路:队列特点,先进先出;栈特点,先进后出,自然可以通过两个栈来回倒换,形成先进先出的特点,用以实现队列。
代码:
var CQueue = function() {
this.stack1 = new Array();
this.stack2 = new Array();
};
/**
* @param {number} value
* @return {void}
*/
CQueue.prototype.appendTail = function(value) {
this.stack1.push(value);
};
/**
* @return {number}
*/
CQueue.prototype.deleteHead = function() {
if(this.stack1.length==0){
return -1;
}else{
while(this.stack1.length>0){
let val = this.stack1.pop();
this.stack2.push(val);
}
let val = this.stack2.pop();
while(this.stack2.length>0){
let val = this.stack2.pop();
this.stack1.push(val);
}
return val;
}
};
2.包含min函数的栈
日期:2023-3-2
链接:点击此处
解题思路:题目的关键是:调用 min、push 及 pop 的时间复杂度都是 O(1),其中难点在于min要求O(1),好在我们有2个栈,那么通过空间换时间,在第二个栈中,保存当前时间片所在的最小值,使用minNumber变量来维护这个最小值。
代码:
/**
* initialize your data structure here.
*/
var MinStack = function() {
this.stack1 = [];
this.stack2 = [];
this.minNumber = Number.MAX_VALUE;
};
/**
* @param {number} x
* @return {void}
*/
MinStack.prototype.push = function(x) {
this.stack1.push(x);
if(this.minNumber>x){
this.minNumber = x;
}
this.stack2.push(this.minNumber);
};
/**
* @return {void}
*/
MinStack.prototype.pop = function() {
this.stack1.pop();
this.stack2.pop();
let length = this.stack2.length;
if(length==0){
this.minNumber = Number.MAX_VALUE;
}else{
this.minNumber = this.stack2[length-1];
}
};
/**
* @return {number}
*/
MinStack.prototype.top = function() {
let length = this.stack1.length;
if(length==0){
return null;
}else{
return this.stack1[length-1];
}
};
/**
* @return {number}
*/
MinStack.prototype.min = function() {
return this.minNumber;
};
/**
* 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()
*/
3.从尾到头打印链表
日期:2023-2-26
链接:点击此处
解题思路:遍历链表,把值放入数组,在进行reverse操作
代码:
/**
* @param {ListNode} head
* @return {number[]}
*/
var reversePrint = function(head) {
let p = head;
let arrs = [];
while(p!=null){
arrs.push(p.val);
p = p.next;
}
return arrs.reverse();
};
4.反转链表
日期:2023-2-26
链接:点击此处
解题思路:使用pre和current两个节点,遍历反转,注意反转的顺序。
代码:
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var reverseList = function(head) {
let pre = null;
let current = head;
while(current!=null){
let tmp = current;
current = current.next;
tmp.next = pre;
pre = tmp;
}
return pre;
};
5.复杂链表的复制
日期:2023-3-7
链接:点击此处
解题思路:常规的链表复制,创建新链表,遍历待复制链表,将节点信息拷贝到新链表中即可。此处特殊之处在于需要维护一个random节点,在第一次遍历过程中,新链表的random节点可能还没创建,所以需要2次遍历,第2次遍历用来维护新链表的random关系,使用map维护新旧链表的对应关系,从而维护新链表的对应关系。
代码:
/**
* // Definition for a Node.
* function Node(val, next, random) {
* this.val = val;
* this.next = next;
* this.random = random;
* };
*/
/**
* @param {Node} head
* @return {Node}
*/
var copyRandomList = function(head) {
let p = head;
let hashTable = new Map();
let newList = new Node();
let newListHeader = newList;
while(p!=null){
let node = new Node(p.val);
hashTable.set(p,node);
newList.next = node;
newList = newList.next;
p = p.next;
}
p = head;
newList = newListHeader.next;
while(p!=null){
newList.random = hashTable.get(p.random);
newList = newList.next;
p = p.next;
}
return newListHeader.next;
};
6.替换空格
日期:2023-3-7
链接:点击此处
解题思路:string是不可变变量,新建一个string变量,进行遍历拷贝。
代码:
var replaceSpace = function(s) {
let str = '';
for(let i=0;i<s.length;i++){
if(s.charAt(i) === ' '){
str+='%20';
}else{
str+=s.charAt(i);
}
}
return str;
};
7.左旋转字符串
日期:2023-3-7
链接:点击此处
解题思路:字符串拼接法
代码:
var reverseLeftWords = function(s, n) {
return(s.substring(n)+s.slice(0,n));
};
8.数组中重复的数字
日期:2023-3-7
链接:点击此处
解题思路:考察朴素的hashmap
代码:
/**
* @param {number[]} nums
* @return {number}
*/
var findRepeatNumber = function(nums) {
let arr = new Array(nums.length).fill(0);
for(let i=0;i<nums.length;i++){
if(arr[nums[i]]==0){
arr[nums[i]]++;
}else{
return nums[i];
}
}
return null;
};
9.在排序数组中查找数字 I
日期:2023-3-7
链接:点击此处
解题思路:二分查找
代码:
/**
* @param {number[]} nums
* @return {number}
*/
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
const binarySearch = (nums, target, lower) => {
let left = 0, right = nums.length - 1, ans = nums.length;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (nums[mid] > target || (lower && nums[mid] >= target)) {
right = mid - 1;
ans = mid;
} else {
left = mid + 1;
}
}
return ans;
}
var search = function(nums, target) {
let ans = 0;
const leftIdx = binarySearch(nums, target, true);
const rightIdx = binarySearch(nums, target, false) - 1;
if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] === target && nums[rightIdx] === target) {
ans = rightIdx - leftIdx + 1;
}
return ans;
};
10.0~n-1中缺失的数字
日期:2023-3-7
链接:点击此处
解题思路:考察桶排序
代码:
/**
* @param {number[]} nums
* @return {number}
*/
var missingNumber = function(nums) {
let arr = new Array(nums.length+1);
for(let i=0;i<nums.length;i++){
arr[nums[i]] = 1;
}
for(let i=0;arr.length;i++){
if(!arr[i]){
return i;
}
}
return null;
};
11.二维数组中的查找
日期:2023-3-8
链接:点击此处
解题思路:从斜对角线的两点进行查询(空间二分查找)
代码:
/**
* @param {number[][]} matrix
* @param {number} target
* @return {boolean}
*/
var findNumberIn2DArray = function(matrix, target) {
let n = matrix.length;
let m = n>0?matrix[0].length:0;
let i = m-1;
let j = 0;
while(i>=0&j<n){
if(matrix[j][i] == target){
return true;
}else if(matrix[j][i] > target){
i--;
}else{
j++;
}
}
return false;
};
12.旋转数组的最小数字
日期:2023-3-8
链接:点击此处
解题思路:二分查找的变形
代码:
/**
* @param {number[]} numbers
* @return {number}
*/
var minArray = function(numbers) {
let low = 0;
let high = numbers.length - 1;
while (low < high) {
const pivot = low + Math.floor((high - low) / 2);
if (numbers[pivot] < numbers[high]) {
high = pivot;
} else if (numbers[pivot] > numbers[high]) {
low = pivot + 1;
} else {
high -= 1;
}
}
return numbers[low];
};
13.第一个只出现一次的字符
日期:2023-3-9
链接:点击此处
解题思路:使用哈希Map进行遍历然后求值
代码:
/**
* @param {string} s
* @return {character}
*/
var firstUniqChar = function (s) {
let map = new Map();
for (let i = 0; i < s.length; i++) {
if (!map.has(s.charAt(i))) {
map.set(s.charAt(i), 1);
} else {
map.set(s.charAt(i), map.get(s.charAt(i)) + 1);
}
}
for (let i = 0; i < s.length; i++) {
if (map.has(s.charAt(i)) && map.get(s.charAt(i)) === 1) {
return s.charAt(i);
}
}
return ' ';
};
firstUniqChar("leetcode");
14.从上到下打印二叉树
日期:2023-3-9
链接:点击此处
解题思路:二叉树的广度优先遍历(利用队列)
代码:
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var levelOrder = function (root) {
let queue = [];
let arr = [];
if (root != null) {
queue.push(root);
while (queue.length != 0) {
let node = queue[0];
arr.push(node.val);
queue.shift();
if (node.left) {
queue.push(node.left);
}
if (node.right) {
queue.push(node.right);
}
}
return arr;
} else {
return [];
}
};
15.从上到下打印二叉树 II
日期:2023-3-9
链接:点击此处
解题思路:二叉树的广度优先遍历(利用队列)
代码:
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
function TreeNodeLevel(treeNode,level){
this.node = treeNode;
this.level = level;
}
var levelOrder = function (root) {
let queue = [];
let arr = [];
if (root != null) {
queue.push(new TreeNodeLevel(root,0));
while (queue.length != 0) {
let treeNode = queue[0];
const {node,level} = treeNode;
if(!arr[level]){
arr[level] = [];
}
arr[level].push(node.val);
queue.shift();
if (node.left) {
queue.push(new TreeNodeLevel(node.left,level+1));
}
if (node.right) {
queue.push(new TreeNodeLevel(node.right,level+1));
}
}
return arr;
} else {
return [];
}
};
15.二叉树的镜像
日期:2023-3-10
链接:点击此处
解题思路:递归
代码:
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var mirrorTree = function(root) {
if(root==null){
return root;
}
mirrorTree(root.left);
mirrorTree(root.right);
let tmp = root.left;
root.left = root.right;
root.right = tmp;
return root;
};
16.二叉树的镜像
日期:2023-3-11
链接:点击此处
解题思路:二叉树的前序遍历和递归
代码:
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} A
* @param {TreeNode} B
* @return {boolean}
*/
var isSubStructure = function(A, B) {
return (A != null && B != null) && (recur(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B));
};
var recur = function(A, B) {
if(B == null) return true;
if(A == null || A.val != B.val) return false;
return recur(A.left, B.left) && recur(A.right, B.right);
}
17.删除链表的节点
日期:2023-3-13
链接:点击此处
解题思路:双指针
代码:
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} val
* @return {ListNode}
*/
var deleteNode = function(head, val) {
let pre=null;
let current = head;
while(current!=null){
if(current.val == val){
if(pre==null){
return current.next;
}else{
pre.next = current.next;
return head;
}
}else{
pre = current;
current = current.next;
}
}
};
18.链表中倒数第k个节点
日期:2023-3-13
链接:点击此处
解题思路:双指针
代码:
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} k
* @return {ListNode}
*/
var getKthFromEnd = function(head, k) {
let current = head;
let pre = null;
let i =0;
while(current!=null){
current = current.next;
i++;
if(pre){
pre = pre.next;
}
if(i==k){
pre = head;
}
}
return pre;
};
19.二叉树的深度
日期:2023-3-15
链接:点击此处
解题思路:树的深度优先遍历
代码:
var maxDepth = function(root) {
if(root==null){
return 0;
}else{
let left = maxDepth(root.left);
let right = maxDepth(root.right);
return left>right?left+1:right+1;
}
};
20.平衡二叉树
日期:2023-3-15
链接:点击此处
解题思路:树的深度优先遍历及平衡二叉树的定义
代码:
var isBalanced = function(root) {
if(root==null){
return true;
}else{
let res = Math.abs(maxDepth(root.left)-maxDepth(root.right));
return res<=1&isBalanced(root.left)&isBalanced(root.right);
}
};
var maxDepth = function(root) {
if(root==null){
return 0;
}else{
let left = maxDepth(root.left);
let right = maxDepth(root.right);
return left>right?left+1:right+1;
}
};
21.连续子数组的最大和
日期:2023-3-20
链接:点击此处
解题思路:我们用f(i)代表以第i数结尾的「连续子数组的最大和」,那么很显然我们要求的答案就是:0≤i≤n−1max{f(i)},定义状态转移方程,f(i)=max{f(i−1)+nums[i],nums[i]}
代码:
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
let pre = 0, maxAns = nums[0];
nums.forEach((x) => {
pre = Math.max(pre + x, x);
maxAns = Math.max(maxAns, pre);
});
return maxAns;
};
22.礼物的最大价值
日期:2023-3-20
链接:点击此处
解题思路:当前最大值为其本身和其上及其左数据的最大值的和。
代码:
/**
* @param {number[][]} grid
* @return {number}
*/
var maxValue = function(grid) {
let m = grid.length;
let n = grid[0].length;
for(let i=0;i<m;i++){
for(let j=0;j<n;j++){
let up_x = i-1;
let up_y = j;
let up = 0;
if(up_x>=0&up_y>=0){
up = grid[up_x][up_y];
}
let left_x = i;
let left_y = j-1;
let left = 0;
if(left_x>=0&&left_y>=0){
left = grid[left_x][left_y];
}
grid[i][j] +=Math.max(up,left);
}
}
return grid[m-1][n-1];
};
刷题盖楼模板
### 序号:[题目名称]
日期:[输入刷题日期]
链接:[点击此处](xxxx)
解题思路:[N关键字清晰总结解题思路]
代码:[拷贝代码,以JS代码为例]