力扣503. 下一个更大元素 II---先进后出单调栈

503. 下一个更大元素 II

给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。

示例 1:

输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数; 
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
注意: 输入数组的长度不会超过 10000。

题解:

此题与另一题力扣739. 每日温度–暴力法与单调栈类似,有兴趣可以看一下。并且我对于单调栈问题的启蒙来自于里面的一个视频,如果不是很明白栈的问题可以看一下里面的视频。

首先我们需要先分析一下题意,我们所求的是这个循环数组中每个元素的下一个更大元素,没有则输出-1。这一题第一个难点在于循环数组
假如不是循环数组,那么我们可以看出来这是一个“先进后出”的题目,妥妥的使用来解决。
即我们构建一个数组模拟栈,接着遍历一遍nums数组,如果栈内为空直接将对应的nums[i]入栈,否则则进行以下判断:
1.栈外元素大于栈顶元素,此时满足题意“下一个更大元素”,所以我们使用arr数组将每个元素对应的最大元素存储起来。为了栈顶元素下面的元素与栈外元素比较,所以我们应该让栈顶元素出栈,且你找到的那个更大元素也可以成为别的元素的更大元素,所以需要再用一下它,即nums数组进行一个类似于“回溯”的操作。
2.栈外元素不大于栈顶元素,即我们没有找到所谓 “下一个更大元素”,所以栈外元素入栈即可。

经过上述比较我们即可找出满足题意的arr数组,但是注意此题为“循环数组”。
那么首先我们需要思考怎么模拟所谓的“循环”状态呢?
你需要知道的是----对于线性遍历常使用for循环结构,对于环状遍历则常使用while循环结构。

因此我们这里在遍历nums1时使用while循环。

并且这里有一个要点,为了形成所谓的环状,我们只要查找两遍nums1即可。
为什么呢?你发现所谓的环状不过是每一次对单个元素查找时是在原先的数组的空间范围进行查找的。
举个例子:1,2,4,5,1,对于1,我们需要查找2,接着4,5,1查找的过程中发现大于1的直接退出即可。但我们给他分配的查找空间是整个nums1数组;对于2,查找的是4,5,1,1即加上2本身的话也是在整个nums1数组里查找;同理对于4,查找为5,1,1,2也是整个nums1数组。所以对于每个元素我们都是在整个nums1数组的空间范围上进行查找的,并且我们发现对于第一个元素1遍历一遍nums1即可,对于2遍历一遍nums1后还要再遍历第一个1,对于4还要再遍历第一个1和第二个2,而对于最后一个1来说我们发现遍历的相当于是两次nums1,因此最大只是相当于遍历两次nums1,所以我们直接遍历两遍nums1一定能遍历完全,而对于一些元素来说能找到“更大元素”的话你遍历一次nums1自然就已经找到了,而找不到你找再多次也是没有用的,因此通过这个细节我们就可以完成环状数组的操作。

并且栈中我们需要存放的不是元素值了,应该是存放nums数组里元素的下标,因为我们后续需要给arr数组赋值时要按照对应的位置来,通过存储下标我们更容易找到nums中元素对应的位置,进而完成一种映射的处理

代码:

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* nextGreaterElements(int* nums, int numsSize, int* returnSize){
    
    
   int*arr=(int*)malloc(sizeof(int)*numsSize);//真正返回的数组
   int*temp=(int*)malloc(sizeof(int)*numsSize*2); //注意可能有不会出栈的情况,
   //而我们遍历2次nums1,因此需要两倍的大小
   memset(arr,-1,sizeof(int)*numsSize);//先变成-1
   int top = 0;//栈顶下标
   int i = 0;//此代表你遍历的元素个数
   while(i<2*numsSize-1)//最后一个不找是可以的
   //因为只有最后一个元素会受到“找完”的待遇,而自己本身又不会大于自己
   {
    
    
       int k = 0;
       k=i%numsSize;//取余操作是为了找到真正的环状数组元素对应的下标
       if(top==0)
       {
    
    
           temp[top]=k;
           top++;
           i++;
           continue;
       }
       else
       {
    
    
           if(nums[k]>nums[temp[top-1]])
           {
    
    
               arr[temp[top-1]]=nums[k];//存储进去
               top--;//不出栈比较不了后面的了
               i--;//回溯
           }
           else
           {
    
    
               temp[top]=k;
               top++;
           }
           i++;
           continue;
       }
   }
   *returnSize=numsSize;//表明返回的真正长度
    return arr;
}

猜你喜欢

转载自blog.csdn.net/xiangguang_fight/article/details/112789742
今日推荐