LeetCode剑指 Offer(27)

Posted 戊子仲秋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode剑指 Offer(27)相关的知识,希望对你有一定的参考价值。

目录

题目:剑指 Offer 53 - I. 在排序数组中查找数字 I - 力扣(Leetcode)

题目的接口:

解题思路:

代码:

过啦!!!

写在最后:


题目:剑指 Offer 53 - I. 在排序数组中查找数字 I - 力扣(Leetcode)

题目的接口:

class Solution 
public:
    int search(vector<int>& nums, int target) 

    
;

解题思路:

那么这道题呢,

如果只是作为一道题,或者说笔试题,

我们当然是二话不说直接暴力拿下,

来看代码:

class Solution 
public:
    int search(vector<int>& nums, int target) 
        int cnt = 0;
        for(auto e : nums) if(e == target) cnt++;
        return cnt;        
    
;

是的,就是这么简单,三行代码暴力拿下,

但是,很显然,这道题肯定不只是让你随便暴力拿下,

如果是在面试的时候,面试官让你讲讲这道题,你确实可以先给面试官

讲讲暴力的解法,但要是你只会暴力,那估计就要直接回家等通知了,

很显然,作为一个有序数组,这道题可以用二分进行优化:

我们可以通过二分法确定左右边界,然后让右边界 - 左边界 + 1求出答案。

具体思路如下:

先确定右边界:(让左下标一直往右边靠)

如果 nums[mid] <= target,就让 left = mid + 1;

 让左下标一直往右边走:

 直到走出taget位置,让右下标往右靠:

这样 left > right ,循环结束,找到右边界left,

特殊情况:

1. 如果数组内不存在target,right所在位置就不是target;

2. 如果数组不存在target且数组内所以元素都 > target 或者 数组根本没有元素,right就 < 0

也就是right会跑出数组,甚至本来就不在数组里面,

这两种情况就直接返回 0 表示不存在 target 值。

接下来是确定左边界,我们现将求出的右边界存下来:

(让右下标一直往左走)

如果 nums[mid] < target,就让 left = mid + 1;

 如果 nums[mid] >= target,就让 right = mid - 1;

 让右下标一直往左走:

 这样 left > right ,循环结束,找到左边界right,

 最后再让 右边界 - 左边界 + 1 即可,

下面是具体代码:

代码:

class Solution 
public:
    int search(vector<int>& nums, int target) 
        //先确定右边界
        int left = 0, right = nums.size() - 1;
        while(left <= right) 
            int mid = (left + right) >> 1;
            if(nums[mid] <= target) left = mid + 1;
            else right = mid - 1;
        

        //右边界如果跑出数组或者所在位置不等于target,证明数组内没有target,就直接返回0
        if(right < 0 || nums[right] != target) return 0;

        //将右边界存下来
        int r = right;

        //再确定左边界
        left = 0, right = nums.size() - 1;
        while(left <= right) 
            int mid = (left + right) >>  1;
            if(nums[mid] < target) left = mid + 1;
            else right = mid - 1;
        

        //返回:右边界 - 左边界 + 1
        return r - left + 1;
    
;

过啦!!!

写在最后:

以上就是本篇文章的内容了,感谢你的阅读。

如果喜欢本文的话,欢迎点赞和评论,写下你的见解。

如果想和我一起学习编程,不妨点个关注,我们一起学习,一同成长。

之后我还会输出更多高质量内容,欢迎收看

剑指 Offer(第 2 版)完整题解笔记 & C++代码实现(LeetCode版)

文章目录

原书目录

剑指 Offer 03. 数组中重复的数字
剑指 Offer 04. 二维数组中的查找
剑指 Offer 05. 替换空格
剑指 Offer 06. 从尾到头打印链表
剑指 Offer 07. 重建二叉树
剑指 Offer 09. 用两个栈实现队列
剑指 Offer 10- I. 斐波那契数列
剑指 Offer 10- II. 青蛙跳台阶问题
剑指 Offer 11. 旋转数组的最小数字
剑指 Offer 12. 矩阵中的路径
剑指 Offer 13. 机器人的运动范围
剑指 Offer 14- I. 剪绳子
剑指 Offer 14- II. 剪绳子 II
剑指 Offer 15. 二进制中1的个数
剑指 Offer 16. 数值的整数次方
剑指 Offer 17. 打印从1到最大的n位数
剑指 Offer 18. 删除链表的节点
剑指 Offer 19. 正则表达式匹配
剑指 Offer 20. 表示数值的字符串
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
剑指 Offer 22. 链表中倒数第k个节点
剑指 Offer 24. 反转链表
剑指 Offer 25. 合并两个排序的链表
剑指 Offer 26. 树的子结构
剑指 Offer 27. 二叉树的镜像
剑指 Offer 28. 对称的二叉树
剑指 Offer 29. 顺时针打印矩阵
剑指 Offer 30. 包含min函数的栈
剑指 Offer 31. 栈的压入、弹出序列
剑指 Offer 32 - I. 从上到下打印二叉树
剑指 Offer 32 - II. 从上到下打印二叉树 II
剑指 Offer 32 - III. 从上到下打印二叉树 III
剑指 Offer 33. 二叉搜索树的后序遍历序列
剑指 Offer 34. 二叉树中和为某一值的路径
剑指 Offer 35. 复杂链表的复制
剑指 Offer 36. 二叉搜索树与双向链表
剑指 Offer 37. 序列化二叉树
剑指 Offer 38. 字符串的排列
剑指 Offer 39. 数组中出现次数超过一半的数字
剑指 Offer 40. 最小的k个数
剑指 Offer 41. 数据流中的中位数
剑指 Offer 42. 连续子数组的最大和
剑指 Offer 43. 1~n 整数中 1 出现的次数
剑指 Offer 44. 数字序列中某一位的数字
剑指 Offer 45. 把数组排成最小的数
剑指 Offer 46. 把数字翻译成字符串
剑指 Offer 47. 礼物的最大价值
剑指 Offer 48. 最长不含重复字符的子字符串
剑指 Offer 49. 丑数
剑指 Offer 50. 第一个只出现一次的字符
剑指 Offer 51. 数组中的逆序对
剑指 Offer 52. 两个链表的第一个公共节点
剑指 Offer 53 - I. 在排序数组中查找数字 I
剑指 Offer 53 - II. 0~n-1中缺失的数字
剑指 Offer 54. 二叉搜索树的第k大节点
剑指 Offer 55 - I. 二叉树的深度
剑指 Offer 55 - II. 平衡二叉树
剑指 Offer 56 - I. 数组中数字出现的次数
剑指 Offer 56 - II. 数组中数字出现的次数 II
剑指 Offer 57 - II. 和为s的连续正数序列
剑指 Offer 57. 和为s的两个数字
剑指 Offer 58 - I. 翻转单词顺序
剑指 Offer 58 - II. 左旋转字符串
剑指 Offer 59 - I. 滑动窗口的最大值
剑指 Offer 59 - II. 队列的最大值
剑指 Offer 60. n个骰子的点数
剑指 Offer 61. 扑克牌中的顺子
剑指 Offer 62. 圆圈中最后剩下的数字
剑指 Offer 63. 股票的最大利润
剑指 Offer 64. 求1+2+…+n
剑指 Offer 65. 不用加减乘除做加法
剑指 Offer 66. 构建乘积数组
剑指 Offer 67. 把字符串转换成整数
剑指 Offer 68 - I. 二叉搜索树的最近公共祖先
剑指 Offer 68 - II. 二叉树的最近公共祖先

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

找出数组中重复的数字。

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

示例 1:

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

限制:

2 <= n <= 100000

class Solution 
public:
    int findRepeatNumber(vector<int>& nums) 
        set<int>se;
        int ok = nums[0];
        for(int x : nums)
            if(se.count(x))
                ok = x;
                break;
            
            se.insert(x);
        
        return ok;
    
;

剑指 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。

限制:

0 <= n <= 1000

0 <= m <= 1000

class Solution 
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) 
        for(const auto& row : matrix)
            auto it = lower_bound(row.begin(),row.end(),target);
            if(it!=row.end() && *it==target)
                return true;
            
        
        return false;
    
;

剑指 Offer 05. 替换空格

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

示例 1:

输入:s = “We are happy.”
输出:“We%20are%20happy.”

限制:

0 <= s 的长度 <= 10000

class Solution 
public:
    string replaceSpace(string s) 
        string t = "";
        for(char ch : s)
            if(ch!=' ')t += ch;
            else t += "%20";
        
        return t;
    
;

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

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

示例 1:

输入:head = [1,3,2]
输出:[2,3,1]

限制:

0 <= 链表长度 <= 10000

/**
 * 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) 
        vector<int>res;
        ListNode* cur = head;
        while(cur)
            res.push_back(cur->val);
            cur = cur->next;
        
        reverse(res.begin(), res.end());
        return res;
    
;

剑指 Offer 07. 重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。

假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

示例 1:

Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
示例 2:

Input: preorder = [-1], inorder = [-1]
Output: [-1]

限制:

0 <= 节点个数 <= 5000

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) 
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) 
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) 
 * ;
 */
class Solution 
public:
    unordered_map<int, int> index;
    TreeNode * build(vector<int>& preorder, vector<int>& inorder, int pl, int pr, int il, int ir)
        if(pl > pr)return nullptr;
        //根节点
        int prt = pl;
        int irt = index[preorder[prt]];
        //
        TreeNode* root = new TreeNode(preorder[prt]);
        int lsz = irt-il;
        root->left = build(preorder, inorder, pl+1,pl+lsz, il, irt-1);
        root->right = build(preorder, inorder, pl+lsz+1,pr, irt+1,ir);
        return root;
    
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) 
        int n = preorder.size();
        for(int i = 0; i < n; i++)
            index[inorder[i]] = i;
        
        return build(preorder, inorder, 0,n-1, 0, n-1);
    
;

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

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

示例 1:

输入:
[“CQueue”,“appendTail”,“deleteHead”,“deleteHead”]
[[],[3],[],[]]
输出:[null,null,3,-1]
示例 2:

输入:
[“CQueue”,“deleteHead”,“appendTail”,“appendTail”,“deleteHead”,“deleteHead”]
[[],[],[5],[2],[],[]]
输出:[null,-1,null,null,5,2]
提示:

1 <= values <= 10000
最多会对 appendTail、deleteHead 进行 10000 次调用

class CQueue 
public:
    stack<int>in, out;

    CQueue() 
    
    void appendTail(int value) 
        in.push(value);
    
    
    int deleteHead() 
        if(out.empty())
            if(in.empty())return -1;
            else
                while(!in.empty())
                    out.push(in.top());  in.pop();
                
            
        
        int x = out.top();
        out.pop();
        return x;
    
;

/**
 * Your CQueue object will be instantiated and called as such:
 * CQueue* obj = new CQueue();
 * obj->appendTail(value);
 * int param_2 = obj->deleteHead();
 */

剑指 Offer 10- I. 斐波那契数列

写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:

F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

示例 1:

输入:n = 2
输出:1
示例 2:

输入:n = 5
输出:5

提示:

0 <= n <= 100

class Solution 
public:
    int fib(int n) 
        if(n==0)return 0;
        if(n==1)return 1;
        int a = 0, b = 1, mod = 1e9+7;
        for(int i = 2; i <= n; i++)
            int c = b;
            b = (a+b)%mod;
            a = c;
        
        return b;
    
;

剑指 Offer 10- II. 青蛙跳台阶问题

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

示例 1:

输入:n = 2
输出:2
示例 2:

输入:n = 7
输出:21
示例 3:

输入:n = 0
输出:1
提示:

0 <= n <= 100

class Solution 
public:
    int mod = 1e9+7;
    int numWays(int n) 
        if(n<=1)return 1;
        vector<int>f(n+1,0);
        f[0] = 1;  f[1] = 1;
        for(int i = 2; i <= n; i++)
            f[i] = (f[i-1]+f[i-2])%mod;
        
        return f[n];
    
;

剑指 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]] 。

示例 1:

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

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

提示:

n == numbers.length
1 <= n <= 5000
-5000 <= numbers[i] <= 5000
numbers 原来是一个升序排序的数组,并进行了 1 至 n 次旋转

class Solution 
public:
    int minArray(vector<int>& numbers) 
        int l = 0, r = numbers.size()-1;
        while(l < r)
            int mid = l+r>>1;
            if(numbers[r]>numbers[mid])
                r = mid;
            else if(numbers[r]<numbers[mid])
                l = mid+1;
            else r--;
        
        return numbers[l];
    
;

剑指 Offer 12. 矩阵中的路径

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

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

例如,在下面的 3×4 的矩阵中包含单词 “ABCCED”(单词中的字母已标出)。

示例 1:

输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
输出:true
示例 2:

输入:board = [[“a”,“b”],[“c”,“d”]], word = “abcd”
输出:false

提示:

m == board.length
n = board[i].length
1 <= m, n <= 6
1 <= word.length <= 15
board 和 word 仅由大小写英文字母组成

class Solution 
public:
    //check(i,j,k)表示从(i,j)出发,能否搜索到单词word[k..n]
    bool check(vector<vector<char>>&board, string& word, vector<vector<int>>&vis, int i, int j, int k)
        int n = board.size(), m = board[0].size();
        if(board[i][j] != word[k])return false;
        else if(k==word.size()-1)return true;
        vis[i][j] = true;
        vector<pair<int,int> >d0,1,0,-1,1,0,-1,0;
        bool ok = false;
        for(auto dd : d)
            int ni = i+dd.first, nj = j+dd.second;
            if(ni>=0&&ni<n&&nj>=0&&nj<m&&!vis[ni][nj])
                if(check(board,word,vis,ni,nj,k+1))
                    ok = true;
                    break;
                
            
        
        vis[i][j] = false;
        return ok;
    
    bool exist(vector<vector<char>>& board, string word) 
        int n = board.size(), m = board[0].size();
        vector<vector<int>> vis(n, vector<int>(m));
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++)
                if(check(board,word,vis,i,j,0))
                    return true;
                
            
        
        return false;
    
;

剑指 Offer 13. 机器人的运动范围

地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

示例 1:

输入:m = 2, n = 3, k = 1
输出:3
示例 2:

输入:m = 3, n = 1, k = 0
输出:1
提示:

1 <= n,m <= 100
0 <= k <= 20

class Solution 
public:
    int get(int x)
        int res = 0;
        while(x) res += x%10;  x /= 10; 
        return res;
    
    int movingCount(int m, int n, int k) 
        if(!k)return 1;
        vector<vector<int>>vis(m,vector<int>(n,0));
        vis[0][0] = 1;
        int ans = 1;
        for(int i = 0; i < m; i++LeetCode(剑指 Offer)- 27. 二叉树的镜像

力扣461,剑指offer59-I,59-II,60,61

算法leetcode|剑指 Offer 27. 二叉树的镜像|226. 翻转二叉树(rust很强)

算法leetcode|剑指 Offer 27. 二叉树的镜像|226. 翻转二叉树(rust很强)

算法leetcode|剑指 Offer 27. 二叉树的镜像|226. 翻转二叉树(rust很强)

[LeetCode]剑指 Offer 27. 二叉树的镜像