【力扣】刷题+剑指offer第二版

news2024/12/27 13:56:25

文章目录

  • 题目收藏
    • 不含重复字符的最长子串
    • 最长公共子串
  • 剑指 Offer
    • 剑指 Offer 05. 替换空格
    • 剑指 Offer 03. 数组中重复的数字
    • 剑指 Offer 04. 二维数组中的查找
    • 剑指 Offer 09. 用两个栈实现队列
    • 剑指 Offer 07. 重建二叉树
    • 剑指 Offer 06. 从尾到头打印链表
    • 剑指 Offer 11. 旋转数组的最小数字
    • 剑指 Offer 12. 矩阵中的路径
    • 剑指 Offer 27. 二叉树的镜像
    • 剑指 Offer 28. 对称的二叉树
    • 剑指 Offer 29. 顺时针打印矩阵
    • 剑指 Offer 30. 包含min函数的栈
    • 剑指 Offer 31. 栈的压入、弹出序列
    • 剑指 Offer 32 - I. 从上到下打印二叉树
    • 剑指 Offer 32 - II. 从上到下打印二叉树 II
    • 剑指 Offer 33. 二叉搜索树的后序遍历序列
    • 剑指 Offer 34. 二叉树中和为某一值的路径
    • 剑指 Offer 15. 二进制中1的个数
    • 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
    • 22.链表中倒数第k个节点
    • 剑指 Offer II 022. 链表中环的入口节点
    • 剑指 Offer 24. 反转链表
    • 剑指 Offer 25. 合并两个排序的链表
    • 剑指 Offer 26. 树的子结构
    • 剑指 Offer 39. 数组中出现次数超过一半的数字
    • 剑指 Offer 42. 连续子数组的最大和

题目收藏

不含重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

滑动窗口:左边界l, 右边界i, 右边界从0~len-1,用unordered_map记录字符上一次出现的位置,如果出现过就把左边界移动到max(l,字符上次出现的位置+1)
每次左边界移动,都是从含有一个重复的字符到不包含重复字符

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char,int> last_exist;
        int len=s.size();
        int l=0;
        int ans=0;
        for(int i=0;i<len;i++){
            if(last_exist.find(s[i])==last_exist.end()){
                last_exist[s[i]]=i;
                ans=max(ans,i-l+1);
            }
            else{
                l=max(l,last_exist[s[i]]+1);
                last_exist[s[i]]=i;
                ans=max(ans,i-l+1);
            }
        }
        return ans;
    }
};

在这里插入图片描述

最长公共子串

给定两个字符串,求这两个字符串的不包含数字的最长公共子串的长度。

#include<bits/stdc++.h>

using namespace std;

const int N = 10010;
char s1[N],s2[N];
int res, f[N];
int main()
{
    scanf("%s %s", s1 , s2);
    int l = strlen(s1), r = strlen(s2);
    for (int i = 1; i <= l; i++ )//将s1的长度看作物品数量(对应01背包)
    {
        for (int j = r; j>=1; j--)//s2的长度看作背包容量(对应01背包)
        {
            if (s1[i-1] == s2[j-1] && s1[i-1] > '9' && s2[j-1] > '9')//将s2的每个字符看作物品(体积为1,价值为x,其中x只有满足条件(满足相等)才有价值1,否则为0,<既然都为0了,为啥还要放进背包呢?>)
            {
                f[j] = f[j - 1] + 1;//背包的价值
                res = max(res, f[j]);//res记录每次的最大值
            }
            else f[j] = 0;//都不满足,即所有物品价值为0,所以背包总价值也为0
        }
    }
    printf("%d\n", res);
    return 0;
}

剑指 Offer

剑指 Offer 05. 替换空格

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

  1. c++字符串可以修改,因为i一定小于j,所以可能原地修改
  2. 从后往前,先得出修改后的长度,时间复杂度 O ( n ) O(n) O(n)
    class Solution {
    public:
        string replaceSpace(string s) {
            int n=s.size();
            int num=0;
           
            for(int i=0;i<n;i++)
                if(s[i]==' ') num++;
            s.resize(n + 2 * num);
            for(int i=n-1,j=n-1+num*2;i<j;){ //i,j>=0也可
                if(s[i]==' '){
                    s[j]='0';s[j-1]='2';s[j-2]='%';j-=3;i--;
                }
                while(i>=0 && j>=0 && s[i]!=' ') {//这一直报错,因为当i--后可能变为负的
                    s[j]=s[i];i--;j--;
                }
            }
            return s;
        }
    };
    

剑指 Offer 03. 数组中重复的数字

找出数组中重复的数字。

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3

  1. 哈希表空间 O ( n ) O(n) O(n)

  2. 原地交换时间和哈希一样是 O ( n ) O(n) O(n),空间 O ( 1 ) O(1) O(1)
    在这里插入图片描述

    class Solution {
    public:
        int findRepeatNumber(vector<int>& nums) {
            int i=0;
            while(i<nums.size()){
                if(nums[i]!=i) {
                    if(nums[nums[i]]!=nums[i])//因为都在[0,n)之间,不会越界
                        swap(nums[i],nums[nums[i]]);
                    else return nums[i];
                }
                else i++;
            }
            return -1;
        }
    };
    

剑指 Offer 04. 二维数组中的查找

在一个 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。

基准是右上角或者左下角,这样才可以剔除一行或一列;左上角无法剔除,无法缩小查找范围

class Solution {
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
        int n=matrix.size();
        if(n==0) return false; 
        int m=matrix[0].size();
        int r=0,c=m-1;
        while(r<n && c>=0){
            if(matrix[r][c]==target) return true;
            else if(target<matrix[r][c]) c--;
            else r++;
        }
        return false;
    }
};

剑指 Offer 09. 用两个栈实现队列

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

class CQueue {
    //两个栈,一个出栈,一个入栈
    private Stack<Integer> stack1;
    private Stack<Integer> stack2;
    
    public CQueue() {
        stack1 = new Stack<>();
        stack2 = new Stack<>();
    }
    
    public void appendTail(int value) {
        stack1.push(value);
    }
    
    public int deleteHead() {
        if(!stack2.isEmpty()){
            return stack2.pop();
        }else{
            while(!stack1.isEmpty()){
                stack2.push(stack1.pop());
            }
            return stack2.isEmpty() ? -1 : stack2.pop();
        }
    }
}

剑指 Offer 07. 重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
递推参数: 根节点在前序遍历的索引 root 、子树在中序遍历的左边界 left 、子树在中序遍历的右边界 right

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        this->preorder = preorder;
        for(int i = 0; i < inorder.size(); i++)
            dic[inorder[i]] = i;
        return recur(0, 0, inorder.size() - 1);
    }
private:
    vector<int> preorder;
    unordered_map<int, int> dic;
    TreeNode* recur(int root, int left, int right) { 
        if(left > right) return nullptr;                        // 递归终止
        TreeNode* node = new TreeNode(preorder[root]);          // 建立根节点
        int i = dic[preorder[root]];                            // 划分根节点、左子树、右子树
        node->left = recur(root + 1, left, i - 1);              // 开启左子树递归
        node->right = recur(root + i - left + 1, i + 1, right); // 开启右子树递归
        return node;                                            // 回溯返回根节点
    }
};

剑指 Offer 06. 从尾到头打印链表

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

从头遍历链表,入栈,再出栈。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> reversePrint(ListNode* head) {
        stack<ListNode*> sk;
        vector<int> s;
        ListNode* pNode=head;
        while(pNode!=nullptr){
            sk.push(pNode);
            pNode=pNode->next;
        }
        while(!sk.empty()){
            pNode=sk.top();
            s.push_back(pNode->val);
            sk.pop();
        }
        return s;
    }
};

剑指 Offer 11. 旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。

给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为 1。

注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。

输入:numbers = [3,4,5,1,2]
输出:1
输入:numbers = [2,2,2,0,1]
输出:0

class Solution {
public:
    int minArray(vector<int>& numbers) {
        //二分
        int n=numbers.size();
        int l=0,r=n-1;
        int mid=l;//初始化为l,当numbers直接递增时
        int ans=numbers[0];
        while(numbers[l]>=numbers[r]){
            if(l+1==r) {
                mid=r;break;
            }
            mid=(l+r)>>1;
            if(numbers[mid]==numbers[l] && numbers[mid]==numbers[r]){
                for(int i=0;i<n;i++)
                    ans=min(ans,numbers[i]);
                return ans;
            }
            if(numbers[mid]>=numbers[l]) l=mid;
            else if(numbers[mid]<=numbers[r]) r=mid;
        }
        return numbers[mid];
    }
};
  • 按照旋转规则,第一个元素应该大于等于最后一个元素,特例[1,2,3],此时,不进while()直接return numbers[mid]=numbers[0]
  • 若中间元素位于前面的递增子数组,那么它应该大于等于第一个指针指向的元素—>将第一个指针移到mid
    在这里插入图片描述

剑指 Offer 12. 矩阵中的路径

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

class Solution {
public:
    bool exist(vector<vector<char>>& board, string word) {
        rows = board.size();
        cols = board[0].size();
        for(int i = 0; i < rows; i++) {
            for(int j = 0; j < cols; j++) {
                if(dfs(board, word, i, j, 0)) return true;
            }
        }
        return false;
    }
private:
    int rows, cols;
    bool dfs(vector<vector<char>>& board, string word, int i, int j, int k) {
        if(i >= rows || i < 0 || j >= cols || j < 0 || board[i][j] != word[k]) return false;
        if(k == word.size() - 1) return true;
        board[i][j] = '\0';//已经用过这个字符了
        bool res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) || 
                      dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1);
        board[i][j] = word[k];//回溯到上一层,恢复现场
        return res;
    }
};

剑指 Offer 27. 二叉树的镜像

请完成一个函数,输入一个二叉树,该函数输出它的镜像。
在这里插入图片描述

示例 1:
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]

class Solution {
public:
    TreeNode* mirrorTree(TreeNode* root) {
        if(root == nullptr) return nullptr;
        stack<TreeNode*> stack;
        stack.push(root);
        while (!stack.empty())
        {
            TreeNode* node = stack.top();
            stack.pop();
            if (node->left != nullptr) stack.push(node->left);
            if (node->right != nullptr) stack.push(node->right);
            TreeNode* tmp = node->left;
            node->left = node->right;
            node->right = tmp;
        }
        return root;
    }
};
class Solution {
public:
    TreeNode* mirrorTree(TreeNode* root) {
        if (root == nullptr) return nullptr;
        TreeNode* tmp = root->left;
        root->left = mirrorTree(root->right);
        root->right = mirrorTree(tmp);
        return root;
    }
};

剑指 Offer 28. 对称的二叉树

请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:

bool isSymmetric(Treenode* root){
	if(root==NULL) return false;
	return check(root->left,root->right);
}
bool check(Treenode* u, Treenode* v){
	if(u==NULL && v==NULL) return true;
	if(u==NULL || v==NULL || u->val!=v->val) return false;
    return check(u.left, v.right) && check(u.right, v.left);
}
class Solution {
public:
    bool check(TreeNode *u, TreeNode *v) {
        queue <TreeNode*> q;
        q.push(u); q.push(v);
        while (!q.empty()) {
            u = q.front(); q.pop();
            v = q.front(); q.pop();
            if (!u && !v) continue;
            if ((!u || !v) || (u->val != v->val)) return false;

            q.push(u->left); 
            q.push(v->right);

            q.push(u->right); 
            q.push(v->left);
        }
        return true;
    }

    bool isSymmetric(TreeNode* root) {
        return check(root, root);
    }
};

剑指 Offer 29. 顺时针打印矩阵

观察发现可以一圈一圈地输出,每圈的左上角可以表示成(start,start),循环继续的条件是n>start*2 && m>start*2,每圈可以分为从左到右,从上到下。。四步,每步打印的范围是start~m-1-start。。但是有的圈并不总是由这四步组成

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> res;
        int n=matrix.size();
        if(n==0) return {};
        int m=matrix[0].size();
        int start=0;
        while(n>start*2 && m>start*2){
            int endX=m-1-start;
            int endY=n-1-start;

            for(int i=start;i<=endX;i++) res.push_back(matrix[start][i]);

            for(int i=start+1;i<=endY;i++) res.push_back(matrix[i][endX]);

            if(start<endY) for(int i=endX-1;i>=start;i--) res.push_back(matrix[endY][i]);

            if(start<endX) for(int i=endY-1;i>start;i--) res.push_back(matrix[i][start]);
            start++;
        }
        return res;
    }
};

剑指 Offer 30. 包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

借助一个辅助栈,其包含的是一个非递增序列–>如果新入栈的元素大于之前的最小值,仍然往辅助栈中压入该最小值,否则压入新入栈的元素

class MinStack {
    stack<int> x_stack;
    stack<int> min_stack;
public:
    MinStack() {
        min_stack.push(INT_MAX);
    }
    
    void push(int x) {
        x_stack.push(x);
        min_stack.push(::min(min_stack.top(), x));
    }
    
    void pop() {
        x_stack.pop();
        min_stack.pop();
    }
    
    int top() {
        return x_stack.top();
    }
    
    int min() {
        return min_stack.top();
    }
};

剑指 Offer 31. 栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。

借助一个栈来模拟,先按照压入顺序入栈,如果弹出序列的j在栈顶,就弹出;否则,继续压入…

class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        stack<int> s;
        int n=pushed.size();
        for(int i=0,j=0;i<n;i++){
            s.push(pushed[i]);
            while(j<n &&!s.empty()&& popped[j]==s.top()) {
                s.pop();j++;
            }
        }
        if(s.empty()) return true;
        else return false;
    }
};

剑指 Offer 32 - I. 从上到下打印二叉树

二叉树的层序遍历/BFS

class Solution {
public:
    vector<int> levelOrder(TreeNode* root) {
        if(root==NULL) return {};
        vector<int> res;
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty()){
            auto t=q.front();
            res.push_back(t->val);
            q.pop();
            if(t->left) q.push(t->left);
            if(t->right) q.push(t->right);
        }
        return res;
    }
};

剑指 Offer 32 - II. 从上到下打印二叉树 II

从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行
在这里插入图片描述
因为每次在队列中的都属于同一层。所以,循环q.size()次,对每个结点的处理不变。

vector<vector<int>> levelOrder(TreeNode* root) {
        if(root==NULL) return {};
        queue<TreeNode*> q;
        q.push(root);
        vector<vector<int>> ans;
        while(!q.empty()){
            vector<int> res;
            int cnt=q.size();
            for(int i=0;i<cnt;i++){
                auto t=q.front();
                q.pop();
                if(t->left) q.push(t->left);
                if(t->right) q.push(t->right);
                res.push_back(t->val);  
            }
            ans.push_back(res);  
        }
        return ans;
    }

剑指 Offer 33. 二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

输入: [1,6,3,2,5]
输出: false

输入: [1,3,2,6,5]
输出: true

class Solution {
public:
    bool verifyPostorder(vector<int>& postorder) {
        return verify(postorder,0,postorder.size()-1);
    }
    bool verify(vector<int>& postorder,int left,int right){
        if(left>=right) return true;
        int root=postorder[right];
        int i=left;
        while(i<=right && postorder[i]<root) i++;
        int j=i;
        while(j<=right && postorder[j]>root) j++;//必须是递增的,所哟从i之后的都要大于root
        return j==right && verify(postorder,left,i-1)&&verify(postorder,i,right-1);
    }
};

剑指 Offer 34. 二叉树中和为某一值的路径

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

class Solution {
public:
    vector<vector<int>> ans;
    vector<int> path;
    void dfs(TreeNode* root, int target){
        if(root==nullptr) return;
        target-=root->val;
        path.push_back(root->val);
        if(root->left==nullptr && root->right==nullptr && target==0) ans.push_back(path);
        dfs(root->left,target);
        dfs(root->right,target);
        //回溯时的恢复
        path.pop_back();
    }
    vector<vector<int>> pathSum(TreeNode* root, int target) {        
        dfs(root,target);
        return ans;
    }
};

剑指 Offer 15. 二进制中1的个数

可能输入负数,如0x80000000。负数右移:10001010>>3=11110001

  1. 循环的次数等于整数二进制的位数
    int NumberOf1(int n){
    	int count=0;
    	unsigned int flag=1;
    	while(flag){
    		if(n&flag) count++;
    		flag=flag<<1;
    	}
    	return count; 
    }
    
  2. 二进制数字n中1的个数
    n&(n-1)把n最右边的1变为0
    int NumberOf1(int n){
    	int count=0;
    	while(n){
    		count++;
    		n=n&(n-1);
    	}
    	return count; 
    }
    

剑指 Offer 21. 调整数组顺序使奇数位于偶数前面

在这里插入图片描述

class Solution {
public:
    vector<int> exchange(vector<int>& nums)
    {
        int i = 0, j = nums.size() - 1;
        while (i < j)
        {
            while(i < j && (nums[i] & 1) == 1) i++;
            while(i < j && (nums[j] & 1) == 0) j--;
            swap(nums[i], nums[j]);
        }
        return nums;
    }
};

(nums[i] & 1) == 1)这里是一个判断数字属于数组的前半部分还是后半部分的函数。

22.链表中倒数第k个节点

只遍历链表一次:
思路:第一个指针从头节点开始走k-1步,第二个指针保持不动;从第k步开始,第二个指针也开始从头结点动(由于两个指针相差k-1,所以当第一个指针到末尾时,第二个指针刚好指向倒数第k个节点)

扩展1:求链表的中间结点。一个指针一次走一步,另一个一次走两步;当走得快的指针走到末尾时,走得慢的指针刚好在链表中间。(扩展2:若走得快的追上了走得慢的,说明链表中存在环;没有追上说明一定不存在)

剑指 Offer II 022. 链表中环的入口节点

给定一个链表,返回链表开始入环的第一个节点。 从链表的头节点开始沿着 next 指针进入环的第一个节点为环的入口节点。如果链表无环,则返回 null。
在这里插入图片描述
在这里插入图片描述

第一轮相遇:
fast 走的步数是 slow 步数的 2 倍,即 f = 2 s f=2s f=2s
fast 比 slow 多走了 n 个环的长度,即 f = s + n b f=s+nb f=s+nb
–> f = 2 n b , s = n b f=2nb, s=nb f=2nb,s=nb

目前,slow 指针走过的步数为 nb 步。因此,我们只要想办法让 slow 再走 a 步停下来,就可以到环的入口

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *fast = head, *slow = head;
        while (true) {
            if (fast == nullptr || fast->next == nullptr) return nullptr;
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow) break;
        }
        fast = head;//fast走了a步->slow也走了a步
        while (slow != fast) {
            slow = slow->next;
            fast = fast->next;
        }
        return fast;//不能是head
    }
};

剑指 Offer 24. 反转链表

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* tmp=head;
        ListNode* pPrev=nullptr;
        ListNode* pReversedHead=nullptr;
        while(tmp!=nullptr){
            ListNode* pNext=tmp->next;//防止链表断裂,复制
            if(pNext==nullptr) pReversedHead=tmp;//最后一个结点就是反转后的头结点
            tmp->next=pPrev;
            pPrev=tmp;
            tmp=pNext;//注意这两句的顺序
        }
        return pReversedHead;
    }
};

剑指 Offer 25. 合并两个排序的链表

输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* dump=new ListNode(0);
        ListNode* cur=dump;
        while(l1!=nullptr && l2!=nullptr){
            if(l1->val == l2->val || l1->val > l2->val) {
                cur->next=l2;l2=l2->next;
            }
            else {
                cur->next=l1;l1=l1->next;
            }
            cur=cur->next;
        }
        if(l1==nullptr) cur->next=l2;
        else cur->next=l1;
        return dump->next;
    }
};

递归:

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(l1==nullptr) return l2;
        if(l2==nullptr) return l1;

        ListNode* pMergeHead=nullptr;
        if(l1->val < l2->val){
            pMergeHead=l1;
            pMergeHead->next=mergeTwoLists(l1->next,l2);
        }
        else{
            pMergeHead=l2;
            pMergeHead->next=mergeTwoLists(l1,l2->next);
        }
        return pMergeHead;
    }
};

剑指 Offer 26. 树的子结构

输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)

B是A的子结构, 即 A中有出现和B相同的结构和节点值。
在这里插入图片描述

class Solution {
public:
    bool isSubStructure(TreeNode* A, TreeNode* B) {
        bool result=false;
        if(A!=nullptr && B!=nullptr){//找到节点值相同的点,然后判断其左右子树是否相同
            if(A->val==B->val) result=doesTree1HasTree2(A,B);
            //没找到节点值相同的点,继续找(递归看其左右子树)
            if(!result) result=isSubStructure(A->left,B);
            if(!result) result=isSubStructure(A->right,B);
        }
        return result;
    }
    bool doesTree1HasTree2(TreeNode* A,TreeNode* B){
        if(B==nullptr) return true;//注意这两句的顺序
        if(A==nullptr) return false;

        if(A->val!=B->val) return false;
        return doesTree1HasTree2(A->left,B->left) && doesTree1HasTree2(A->right,B->right);
    }
};

剑指 Offer 39. 数组中出现次数超过一半的数字

摩尔投票法: 核心理念为 票数正负抵消。此方法时间和空间复杂度分别为 O ( N ) O(N) O(N) O ( 1 ) O(1) O(1)
在这里插入图片描述

剑指 Offer 42. 连续子数组的最大和

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int n=nums.size();
        int res=nums[0],before=nums[0],tmp;
        for(int i=1;i<n;i++){
            if(before<=0) tmp=nums[i];
            else tmp=before+nums[i];
            before=tmp;//优化成before=max(),res=max(before)
            res=max(res,tmp);
        }
        return res;
    }
};

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/507067.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【大数据之Hadoop】二十八、生产调优-HDFS集群扩容及缩容

增加或缩减服务器&#xff0c;注意不允许白名单和黑名单同时出现同一个主机。 1 服役新服务器 原有数据节点不能满足数据存储需求时&#xff0c;需要在原有集群的基础上动态增加节点&#xff0c;即动态增加服务器&#xff0c;增加服务器的同时不需要重启集群。 hadoop完全分布…

JVM相关知识点

java内存区域 线程私有的&#xff1a; 程序计数器虚拟机栈本地方法栈 线程共享的&#xff1a; 堆方法区直接内存 程序计数器&#xff1a;记录当前线程执行的位置 当线程切换后能够知道该线程上次运行到哪了 java虚拟机栈&#xff1a; 方法调用的数据通过栈进行传递&#…

一篇文章带你重新回溯单链表的所有

&#x1f349;博客主页&#xff1a;阿博历练记 &#x1f4d7;文章专栏&#xff1a;数据结构与算法 &#x1f69a;代码仓库&#xff1a;阿博编程日记 &#x1f339;欢迎关注&#xff1a;欢迎友友们订阅收藏关注哦 文章目录 &#x1f34c;前言&#x1f4bb;无头单向非循环链表&am…

SSM(Spring、SpringMVC、MyBatis)整合、配置

SpringMVC是一个表述层(前台的页面和后台的servlet)框架&#xff0c;处理浏览器发送到服务器的请求&#xff0c;并且将一些数据响应到浏览器 MyBatis是一个持久层框架&#xff0c;帮助我们连接数据库&#xff0c;访问数据库&#xff0c;操作数据库中的数据 Spring是一个整合型框…

毕业论文相关

毕业论文参考文献和Word保存 一、Word中出现[7-9]多个文献的引用 在正文中选中参考文献角标&#xff0c;右击选择“切换域代码”&#xff0c;参考文献角标[7][8][9]变为{ REF _Ref98345319 \r \h * MERGEFORMAT }{ REF _Ref98345321 \r \h * MERGEFORMAT }{ REF _Ref99390603…

AQS独占锁之ReentrantLock源码调试(JDK8)

前言&#xff1a; 为什么需要学习ReentrantLock? 目前项目开发中使用到的几乎都是分布式锁&#xff0c;平时可能很少用到java自带的锁&#xff1b; 但实际在我们java的源码中&#xff0c;随处可见需要使用锁来保证线程安全&#xff0c;所以还是有必要学习下ReentrantLock。 1…

7.分区表和分桶表

1.创建分区表 create table dept_partition(deptno int,dname string,loc int ) partitioned by (dt string) // 分区字段(date) row format delimited fields terminated by \t; 2.增删改查操作 2.1 插入数据 1&#xff09;导入本地数据 -- 创建一个名字为dt2022-06-14的…

R语言 | 输入与输出

目录 一、认识文件夹 1.1 getwd()函数 1.2 setwd()函数 1.3 file.path()函数 1.4 dir()函数 1.5 list.files()函数 1.6 file.exists()函数 1.7 file.rename()函数 1.8 file.create()函数 1.9 file.copy()函数 ​1.10 file.remove()函数 二、数据输出&#xff1a;ca…

单片机c51中断 — 中断扫描法行列式键盘

项目文件 文件 关于项目的内容知识点可以见专栏单片机原理及应用 的第五章&#xff0c;中断 在第4章中已介绍过行列式键盘的工作原理&#xff0c;并编写了相应的键盘扫描程序。但应注意的是&#xff0c;在单片机应用系统中&#xff0c;键盘扫描只是 CPU 工作的内容之一。CPU …

一文理清 TiDB 与 MySQL 中的常用字符集及排序规则

1. 字符集&#xff08;character set&#xff09; 1.1. 字符集与编码规则 字符集&#xff08;character set&#xff09;即为众多字符的集合。字符集为每个字符分配一个唯一的 ID&#xff0c;称为 “Code Point&#xff08;码点&#xff09;”。编码规则是将 Code Point 转换…

商户查询的缓存——缓存击穿问题

缓存击穿问题也叫热点key问题&#xff0c;就是一个被高并发访问并且缓存重建业务比较复杂的key突然失效了&#xff0c;无数的请求访问会在瞬间给数据库带来巨大的冲击 常见的解决方案有两种&#xff1a; 互斥锁&#xff08;高并发时性能较差&#xff09; 逻辑过期 基于互斥锁方…

ASN.1-PKCS10-x509

在国际标准ITU-T X.690 《Information technology – ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER)》中定义了ASN.1编码规则。对于一般数据类型&#xff08;比如Integer、octe…

【软件工程】自动化测试保证卓越软件工程能力(2)

本次内容我们抽象一个待测试的目标软件产品&#xff0c;产品是基于web开发的。 自动化平台不是独立存在的&#xff0c;必然有一个目标待测试产品&#xff0c;用自动化测试来反映产品功能是否还是好的。 产品抽象v1 第一个版本&#xff0c;使用者&#xff08;USER&#xff09;发…

配置本地Angular环境并使用VsCode调试Angular前端项目

配置本地Angular环境并使用VsCode调试Angular前端项目 配置本地Angular环境部署Node.Js本地环境配置一下环境变量 使用vscode调试Angular安装vscode 配置本地Angular环境 部署Node.Js本地环境 1 从官网下载node.js, 本文为(v16.13.0) 下载地址: https://nodejs.org/dist/v16.…

windows server 2016报错无法打开所需文件install.wim

报错的前提条件: 1.下载原版镜像后,使用UltraISO制作U盘系统盘。 2.正常安装系统,到“安装程序正在启动界面”时弹出错误窗口,报错“Windows无法打开所需的文件 E:\Source\install.win。请确保安装所需的所有文件可用,并重新启动安装。错误代码:0x80070026”。 问题原因…

【MySQL学习】MySQL表的复合查询

文章目录 前言一、案例准备二、基本查询三、多表查询四、子查询4.1 单行子查询4.2 多行子查询4.3 多列子查询4.4 FROM子句中的子查询4.5 合并查询4.5.1 UNION4.5.2 UNION ALL 五、自连接六、内外连接6.1 内连接6.2 外连接6.2.1 左外连接6.2.2 右外连接 前言 对MySQL表的基本查…

大数据系列——Flink理论

概述 Flink是一个对有界和无界数据流进行有状态计算的分布式处理引擎和框架&#xff0c;既可以处理有界的批量数据集&#xff0c;也可以处理无界的实时流数据&#xff0c;为批处理和流处理提供了统一编程模型&#xff0c;其代码主要由 Java 实现&#xff0c;部分代码由 Scala实…

Java——Java选择题复习(1)(Java基础,进程,多线程,操作系统)

1. 下面关于程序编译说法正确的是&#xff08;&#xff09; A. java语言是编译型语言&#xff0c;会把java程序编译成二进制机器指令直接运行 B. java编译出来的目标文件与具体操作系统有关 C. java在运行时才进行翻译指令 D. java编译出来的目标文件&#xff0c;可以运行在任意…

房地产中介迎来重磅文件,但核心目标仍是专业化规范化发展

5月8日下午&#xff0c;住房和城乡建设部、市场监管总局联合刊登重磅文件《关于规范房地产经纪服务的意见》&#xff08;以下简称《意见》&#xff09;&#xff0c;因其涉及对经纪服务收费等具体问题的指导&#xff0c;文件引发市场重点关注。 不过&#xff0c;在系统性梳理文…

Redisson cannot use an unresolved DNS server address问题解决

概述 本文记录Mac IDEA开发&#xff0c;公司 远程办公时遇到的两个问题&#xff0c;记录一下。 问题 cannot use an unresolved DNS server address: [fe80::1%en0]:53 在家里&#xff0c;连上公司的VPN后&#xff0c;即可打开公司内网&#xff0c;远程办公。一切正常。某…