2021-10-26每日刷题打卡
力扣——每日一题
496. 下一个更大元素 I
给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。
请你找出 nums1 中每个元素在 nums2 中的下一个比其大的值。
nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。
示例 1:
输入: nums1 = [4,1,2], nums2 = [1,3,4,2].
输出: [-1,3,-1]
解释:
对于 num1 中的数字 4 ,你无法在第二个数组中找到下一个更大的数字,因此输出 -1 。
对于 num1 中的数字 1 ,第二个数组中数字1右边的下一个较大数字是 3 。
对于 num1 中的数字 2 ,第二个数组中没有下一个更大的数字,因此输出 -1 。
这题有两个方法,第一种节省空间但速度慢,第二种速度快但占用空间较多
第一种:创建一个vector容器v来存放结果,直接for遍历nums1,里面再放上一个for用来遍历nums2,每次遍历nums1新的元素时去nums2里找到和当前nums1相同的元素,找到以后继续遍历,如果有大于它的数就把那个数插入v中并break结束循环,如果没有大于他的数就插入一个-1。当nums1遍历完后结束循环,返回v即可
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
vector<int>v;
int n=nums1.size(),m=nums2.size();
bool b=false;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(b&&nums2[j]>nums1[i])
{
v.push_back(nums2[j]);
break;
}
if(nums1[i]==nums2[j])
{
b=true;
}
}
b=false;
if(v.size()==i)
{
v.push_back(-1);
}
}
return v;
}
};
第二种:要用上map、stack的知识,准备一个unordered_map容器mymap,一个stack容器sta,一个vector容器v。先遍历nums2,从最后一个元素开始遍历,每次遍历判断栈sta顶部元素是否小于当前元素,如果小于就持续出栈,知道栈为空或顶端元素大于当前遍历元素,然后mymap开始记录当前元素之后有无最大值,mymap[nums2[i]]==sta.empty?-1:sta.top(),这里意思是,如果栈为空,说明我们之前遍历过的元素没有大于当前元素的(因为都在前面出栈弹掉了),如果栈不为空,就说明栈顶元素是大于我们当前元素的,把这个元素赋给mymap,事后要将当前元素入栈。遍历完后开始遍历nums1,每次经由mymap[nums[i]]获知当前元素之后有没有大于它的元素。把结果插入v中。最后返回v
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int,int>mymap;
stack<int>sta;
vector<int>v;
int n=nums1.size();
for(int i=nums2.size()-1;i>=0;i--)
{
int num = nums2[i];
while(!sta.empty()&&sta.top()<num)
{
sta.pop();
}
mymap[num]=sta.empty()?-1:sta.top();
sta.push(num);
}
for(int i=0;i<n;i++)
{
v.push_back(mymap[nums1[i]]);
}
return v;
}
};
189. 旋转数组
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
进阶:
尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗?
示例 1:
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右旋转 1 步: [7,1,2,3,4,5,6]
向右旋转 2 步: [6,7,1,2,3,4,5]
向右旋转 3 步: [5,6,7,1,2,3,4]
原本试了下看看能不能把O(1)的算法写出来,结果超时了。。。我还是写简单的吧
准备一个vector容器v,遍历一遍nums,每次在v的(i+k)%nums.size() 位置上放上nums[i]的值(%nums.size()是为了防止数组越界,同时把旋转后的数插入v前面的位置上。),但由于这里没有返回值,是要修改nums里的值,所以我们遍历一遍v把值复制给nums。
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n=nums.size();
vector<int>v(n);
for(int i=0;i<n;i++)
{
v[(i+k)%n]=nums[i];
}
for(int i=0;i<n;i++)
{
nums[i]=v[i];
}
}
};
第二个方法,利用队列queue来进行旋转操作(出队后入队)。准备一个queue容器que,将nums从尾部数据开始依次入队que(先进先出),然后把队头元素出队再入队,一个进行k次,之后队列里的位置就是旋转好的序列了,再把que的数据复制在nums里即可。
class Solution {
public:
void rotate(vector<int>& nums, int k) {
queue<int>que;
int n = nums.size();
int m = k % n;
for(int i=n-1;i>=0;i--)
{
que.push(nums[i]);
}
while(m--)
{
int num=que.front();
que.pop();
que.push(num);
}
for(int i=n-1;i>=0;i--)
{
nums[i]=que.front();
que.pop();
}
}
};
283. 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。
尽量减少不知道咋减少。。。嘛反正是没用额外的数组。
准备两个指针l和r,初始都为0,用两个指针来遍历nums,当l或r大于等于nums.size()时结束循环,如果l当前指向的位置数不为0,则l和r同时++,如果l指向的位置数为0,则r往前移动,直到nums[r]不为0,然后交换l和r位置上的元素(这里要注意r可能会超出nums.size(),所以要加判断如果r大于等于nums.size()就结束循环)。
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int l = 0, r = 0, n = nums.size();
while (r < n)
{
if (nums[l] != 0)
{
l++;
r++;
}
else
{
while (r < n&&nums[r] == 0 )
{
r++;
}
if (r >= n)
{
break;
}
int math = nums[l];
nums[l] = nums[r];
nums[r] = math;
}
}
}
};
167. 两数之和 II - 输入有序数组
给定一个已按照 非递减顺序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。
你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
示例 1:
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
双指针写法,因为这数组是递增的,所以我们可以用头尾双指针来写,一个left=0,一个right=numbers.size()-1,一个vector容器v,开始遍历,每次判断numbers[left]+numbers[right]的值,如果等于目标值就把left和right插入v中,break掉循环并返回v。如果大于目标值,说明number[right]的值过大(总不能是left太大,人家已经最小了),把right–以减小numbers[right]的值。如果小于目标值说明numbers[left]的值过下,把left++。
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int i=0,j=numbers.size()-1;
vector<int>v;
while(i<j)
{
if(numbers[i]+numbers[j]==target)
{
v.push_back(i+1);
v.push_back(j+1);
break;
}
else if(numbers[i]+numbers[j]>target)
{
j--;
}
else
{
i++;
}
}
return v;
}
};