Letbook Cookbook题单——数组5
81. 搜索旋转排序数组 II
难度中等
已知存在一个按非降序排列的整数数组 nums
,数组中的值不必互不相同。
在传递给函数之前,nums
在预先未知的某个下标 k
(0 <= 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:
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10
示例 2:
输入: 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;
}
};