Letbook Cookbook题单——数组5

28 篇文章 0 订阅
10 篇文章 0 订阅

Letbook Cookbook题单——数组5

81. 搜索旋转排序数组 II

难度中等

已知存在一个按非降序排列的整数数组 nums ,数组中的值不必互不相同。

在传递给函数之前,nums 在预先未知的某个下标 k0 <= k < nums.length)上进行了 旋转 ,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,4,4,5,6,6,7] 在下标 5 处经旋转后可能变为 [4,5,6,6,7,0,1,2,4,4]

给你 旋转后 的数组 nums 和一个整数 target ,请你编写一个函数来判断给定的目标值是否存在于数组中。如果 nums 中存在这个目标值 target ,则返回 true ,否则返回 false

你必须尽可能减少整个操作步骤。

示例 1:

输入:nums = [2,5,6,0,0,1,2], target = 0
输出:true

示例 2:

输入:nums = [2,5,6,0,0,1,2], target = 3
输出:false

提示:

  • 1 <= nums.length <= 5000
  • -104 <= nums[i] <= 104
  • 题目数据保证 nums 在预先未知的某个下标上进行了旋转
  • -104 <= target <= 104

进阶:

  • 这是 搜索旋转排序数组 的延伸题目,本题中的 nums 可能包含重复元素。
  • 这会影响到程序的时间复杂度吗?会有怎样的影响,为什么?

暴力

朴实无华不枯燥

class Solution {
public:
    bool search(vector<int>& nums, int target) {
        for(int i:nums)
        if(i==target)
        return true;
        return false;
    }
};

二分

这题是个扩展题,不同点在于加了一个存在相同元素,边界一下子变复杂了,刚开始没相出,看了官方解释后发现自己还是想复杂了,不过在数据范围较小的情况下下面这个方法和暴力也差不多

对于a[l]==a[mid]=a[r]的情况,我们无法判断哪边是有序的,因此我们可以将当前二分区间的左边界加一,右边界减一,然后在新区间上继续二分查找。

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n = (int)nums.size();
        if (!n) {
            return false;
        }
        if (n == 1) {
            return nums[0] == target ? true : false;
        }
        int l = 0, r = n - 1;
        while (l <= r) {
            int mid = (l + r) / 2;
            if (nums[mid] == target) return true;
             if (nums[l] == nums[mid] && nums[mid] == nums[r]) {
                ++l;
                --r;
            } 
            else if (nums[l] <= nums[mid]) {
                if (nums[l] <= target && target < nums[mid]) {
                    r = mid - 1;
                } else {
                    l = mid + 1;
                }
            } else {
                if (nums[mid] < target && target <= nums[n - 1]) {
                    l = mid + 1;
                } else {
                    r = mid - 1;
                }
            }
        }
        return false;
    }
};

84. 柱状图中最大的矩形

难度困难

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例 1:

img

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

示例 2:

img

输入: heights = [2,4]
输出: 4

提示:

  • 1 <= heights.length <=105
  • 0 <= heights[i] <= 104

单调栈

单调栈,当时看过三叶姐一个对于这类题的题解,讲得很好,这题虽然写得有点坎坷,但还是写出来了,不过没有用最优的一个栈一个循环来写

class Solution {
public:
    int largestRectangleArea(vector<int>& h) {
        stack<int>st;
        vector<int>a(h.size()), b(h.size());
        int ans = 0;
        for (int i = 0; i < h.size(); i++)
        {
            a[i] = i-1;
            while (!st.empty() && h[i] <= h[st.top()])
            {
                st.pop();
                if (st.empty())
                    a[i] = -1;
                else
                    a[i] = st.top();
            }
            st.push(i);
        }
        stack<int>st1;
        for (int i = h.size() - 1; i >= 0; i--)
        {
            b[i] = i+1;
            while (!st1.empty() && h[i] <= h[st1.top()])
            {
               st1.pop();
               if (st1.empty())
                   b[i] = h.size();
               else
                   b[i] = st1.top();
            }
            st1.push(i);
        }
        for (int i = 0; i < h.size(); i++)
            ans = max(ans, h[i] * (i - a[i]) + h[i] * (b[i] - i) - h[i]);
        return ans;
    }
};

90. 子集 II

难度中等

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

示例 1:

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

示例 2:

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

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10

挺标准的一个二进制枚举,注意下判重就行,和以前那些题目判重一样,nums[i]和nums[i+1]相等,对nums[i+1]后面的枚举没必要了

当然回溯枚举也可以

二进制枚举

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vector<vector<int>>ans;
        int n=1<<nums.size();
        for(int i=0;i<n;i++)
        {
            vector<int>x;
             bool flag=true;
            for(int j=1;j<nums.size();j++)
            {
                if((i>>j&1)&&!(i>>(j-1)&1)&&nums[j-1]==nums[j])
                {
                    flag=false;
                    break;
                }
            }
               if(flag)
               {
                for(int j=0;j<nums.size();j++)
                {
                    if(i>>j&1)
                    x.push_back(nums[j]);
                }
                ans.push_back(x);
               }
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值