LeetCode刷题——剑指offer中遍历查找题目汇总


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

题目
找出数组中重复的数字。

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

示例 1:

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

限制:

2 <= n <= 100000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof
代码
这个题目非常简单,将每一个数加到集合当中,如果数在集合中就直接返回即可

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        set<int> s;
        for(int i=0; i < nums.size(); i++){
            if(s.count(nums[i]))
                return nums[i];
            else{
                s.insert(nums[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。

限制:

0 <= n <= 1000

0 <= m <= 1000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof
分析
由于从左到右,从上到下都是递增的,所以我们可以选择左下角或右上角作为起始点。如果以左下角为起点,如果比target大则向右查找,如果比target小则向上查找。如果以右上角为起点,如果比target大则向下查找,如果比target小向左查找。
代码

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

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

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

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

示例 1:

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof

分析
方法1:从左向右依次遍历,找出比左侧元素小的元素
方法2:二分法,如果mid的值小于right的值说明待查找的数在mid左侧,如果mid的值大于right说明待查找的数在mid右侧,如果mid的值等于right的值说明待查找的值可能在mid的左边,也有可能mid就是待查找的值
代码

class Solution {
public:
    int minArray(vector<int>& numbers) {
        int left = 0 , mid, right = numbers.size() - 1;
        while(left < right){
            mid = left + (right - left) / 2;
            if(numbers[mid] < numbers[right]){
                right = mid;
            }else if(numbers[mid] > numbers[right]){
                left = mid + 1;
            }else{
                right--;
            }
        }
        return numbers[left];
    }
};

剑指 Offer 50. 第一个只出现一次的字符

题目
在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。

示例 1:

输入:s = “abaccdeff”
输出:‘b’
示例 2:

输入:s = “”
输出:’ ’

限制:

0 <= s 的长度 <= 50000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof
代码

class Solution {
public:
    char firstUniqChar(string s) {
        if(s == ""){
            return ' ';
        }
        map<char, int> m;
        for(int i=0; i < s.size(); i++){
            m[s[i]]++;
        }
        for(int i=0; i < s.size(); i++){
            if(m[s[i]] == 1)
            return s[i];
        }
        return ' ';
    }
};

剑指 Offer 53 - I. 在排序数组中查找数字 I

题目
统计一个数字在排序数组中出现的次数。

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:

输入: nums = [5,7,7,8,8,10], target = 6
输出: 0

提示:

0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums 是一个非递减数组
-109 <= target <= 109

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof
代码

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int cnt=0;
        for(int i=0; i < nums.size(); i++){
            if(nums[i]==target){
                cnt++;
            }
        }
        return cnt;
    }
};

剑指 Offer 53 - II. 0~n-1中缺失的数字

题目
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。

示例 1:

输入: [0,1,3]
输出: 2
示例 2:

输入: [0,1,2,3,4,5,6,7,9]
输出: 8

输入: [0]
输出: 1

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/que-shi-de-shu-zi-lcof
代码

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int cur=0;
        for(int i=0; i < nums.size(); i++){
            if(nums[i] == cur){
                cur++;
            }else{
                return cur;
            }
        }
        return nums[nums.size()-1]+1;
    }
};

剑指 Offer II 006. 排序数组中两个数字之和(双指针)

给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。

函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 0 开始计数 ,所以答案数组应当满足 0 <= answer[0] < answer[1] < numbers.length 。

假设数组中存在且只存在一对符合条件的数字,同时一个数字不能使用两次。

示例 1:

输入:numbers = [1,2,4,6,10], target = 8
输出:[1,3]
解释:2 与 6 之和等于目标数 8 。因此 index1 = 1, index2 = 3 。

示例 2:

输入:numbers = [2,3,4], target = 6
输出:[0,2]

示例 3:

输入:numbers = [-1,0], target = -1
输出:[0,1]

提示:

2 <= numbers.length <= 3 * 104
-1000 <= numbers[i] <= 1000
numbers 按 递增顺序 排列
-1000 <= target <= 1000
仅存在一个有效答案

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kLl5u1

分析
双指针和target进行比较,如果和比target大右指针左移,如果小左指针右移,如果相等直接返回
代码

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int start=0, end=numbers.size()-1;
        while(start <= end){
            if(numbers[start] + numbers[end] == target){
                return vector<int> {start, end};
            }else if(numbers[start] + numbers[end] > target){
                end--;
            }else if(numbers[start] + numbers[end] < target){
                start++;
            }
        }
        return vector<int> {-1, -1};
    }
};

剑指 Offer II 007. 数组中和为 0 的三个数(双指针)

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a ,b ,c ,使得 a + b + c = 0 ?请找出所有和为 0 且 不重复 的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

示例 2:

输入:nums = []
输出:[]

示例 3:

输入:nums = [0]
输出:[]

提示:

0 <= nums.length <= 3000
-105 <= nums[i] <= 105

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/1fGaJU
分析
首先进行排序,排序后任取一个数,然后取反。在这个数之后取双指针,如果左指针和右指针的和小于取反的数左指针右移,否则右指针左移。
代码

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        if(nums.size()<3){
            return {};
        }
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        for(int i=0; i < nums.size()-2; i++){
            if(i > 0 && nums[i]==nums[i-1]) 
            continue;
            int target = -nums[i];
            int left=i+1;
            int right=nums.size()-1;
            while(left < right){
                if(nums[left]+nums[right] == target){
                    ans.push_back({nums[i], nums[left], nums[right]});
                    while(left < right && nums[left]==nums[++left]);
                    while(left < right && nums[right]==nums[--right]);
                }else if(nums[left]+nums[right] > target){
                    right--;
                }else{
                    left++;
                }
            }
        }
        return ans;
    }
};

剑指 Offer II 008. 和大于等于 target 的最短子数组(前缀和)

题目
给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

提示:

1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105

进阶:

如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/2VG8Kg
分析
打表遍历得到前缀和sums,那么i到j的数的和为sums[j]-sums[i],那么问题就变成了sums[j]-sums[i] > target但是这样我们不方便遍历,我们把问题转换成target + sums[i] < sums[j],遍历得到i然后求j是否存在即可。
代码

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int n = nums.size();
        if (n == 0) {
            return 0;
        }
        int ans = INT_MAX;
        vector<int> sums(n + 1, 0); 
        for (int i = 1; i <= n; i++) {
            sums[i] = sums[i - 1] + nums[i - 1];
        }
        for (int i = 1; i <= n; i++) {
            int target = s + sums[i - 1];
            auto bound = lower_bound(sums.begin(), sums.end(), target);
            if (bound != sums.end()) {
                ans = min(ans, static_cast<int>((bound - sums.begin()) - (i - 1)));
            }
        }
        return ans == INT_MAX ? 0 : ans;
    }
};

剑指 Offer II 009. 乘积小于 K 的子数组(双指针,滑动窗口)

题目
给定一个正整数数组 nums和整数 k ,请找出该数组内乘积小于 k 的连续的子数组的个数。

示例 1:

输入: nums = [10,5,2,6], k = 100
输出: 8
解释: 8 个乘积小于 100 的子数组分别为: [10], [5], [2], [6], [10,5], [5,2], [2,6], [5,2,6]。
需要注意的是 [10,5,2] 并不是乘积小于100的子数组。

示例 2:

输入: nums = [1,2,3], k = 0
输出: 0

提示:

1 <= nums.length <= 3 * 104
1 <= nums[i] <= 1000
0 <= k <= 106

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ZVAVXX
分析
双指针,设置左指针和右指针,如果满足条件右指针左移,统计答案, 如果不满足条件移动左指针。
以示例1[10,5,2,6]为例,统计答案的方式如下:

leftright乘积区间满足的子数组满足子数组数
0010[10][10]1
0150[10,5][10],[5],[10, 5]3
02100--0
115[5][5]1
1210[5,2][5], [2],[5,2]3
1360[5,2, 6][5], [2],[5,2],[6],[2,6],[5,2,6]6

从部分情况的表格可以看出每次right满足条件右移一位,答案应该增加right-left+1
代码

class Solution {
public:
    int numSubarrayProductLessThanK(vector<int>& nums, int k) {
        if(k <= 1){
            return 0;
        }
        int ans=0;
        int left=0, right=0, mult=1;
        while(right < nums.size()){
            mult *= nums[right];
            while(mult >= k){
                mult /= nums[left];
                left++;
            }
            ans += right - left + 1;
            right++;
        }
        return ans;
    }
};

剑指 Offer II 010. 和为 k 的子数组

给定一个整数数组和一个整数 k ,请找到该数组中和为 k 的连续子数组的个数。

示例 1 :

输入:nums = [1,1,1], k = 2
输出: 2
解释: 此题 [1,1] 与 [1,1] 为两种不同的情况

示例 2 :

输入:nums = [1,2,3], k = 3
输出: 2

提示:

1 <= nums.length <= 2 * 104
-1000 <= nums[i] <= 1000
-107 <= k <= 107

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/QTMn0o
分析
假设我们求得了nums的前缀和,那么任意连续子数组都可以用pre[j]-pre[i],j>i表示,满足情况pre[j]-pre[i] = k,即pre[j]-k=pre[i], 所以我们在遍历时只遍历j即可,由于pre[i]一定比pre[j]早出现,所以我们不需要保存数组,用一个整数存储即可。
代码

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        int pre = 0;
        map<int, int> m;
        m[0]=1;
        int ans=0;
        for(int i=0; i < nums.size(); i++){
            pre += nums[i];
            int target = pre - k;
            ans += m[target];
            m[pre]++;
        }
        return ans;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艾醒(AiXing-w)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值