LeetCode刷题帖

371 阅读4分钟

目的

为提升自身编码能力,熟悉数据结构和算法,从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代码为例]