next greater element 系列

496. Next Greater Element I

给定两个数组nums1和nums2,nums1是nums2的子集,返回一个数组,这个数组对应nums1中每个数在nums2中按顺序的下一个比他大的值
Input: nums1 = [4,1,2], nums2 = [1,3,4,2].
Output: [-1,3,-1]
Input: nums1 = [2,4], nums2 = [1,2,3,4].
Output: [3,-1]
两个数组都没有重复的数。
思路:首先将nums2的所有数即下一个大树写到map中去。这里采用的是栈结构,如果栈为空或者是递减的,就把元素写入栈,如果当前元素大于栈顶,就持续的出栈写入map,直到不大于栈顶元素。最后栈中可能还有一些数,这些数不做处理。最后的结果是存在下一个最大元素的数都写入到map中了。其他数没有。
然后遍历第一个数组,在map中寻找。找不到就是-1,找到了就是相应键对应的值。
代码如下:
class Solution {
public:
    vector nextGreaterElement(vector& findNums, vector& nums) {
        map inp;
        vector res;
        int n=nums.size();
        stack q;
        for(auto s:nums)
        {
            while(!q.empty()&&q.top()

503. Next Greater Element II

这道题将nums2改成了环状数组,只输入一个数组,而且数组中可能出现重复的数。
我的:思路。第一次循环,元素入栈,第二次循环,元素不入栈,而且,放入map的键不是具体的数,而是元素的下标与他对应的下一个最大数。入栈的也不是具体的数,而是元素的位置。
class Solution {
public:
    vector nextGreaterElements(vector& nums) {
        //仿照第一个题的方法,首先循环一次,栈要把所有的待选元素放入
        //然后再循环一次,这一次不再把元素放进去
        map inp;
        vector res;
        int n=nums.size();
        stack q;
        for(int i=0;i

上述解法的改进版本:
可以不使用map,预先设定res数组的初始值是-1,每次找到一个最大值就更新res中相应的位置。这里使用了取模运算。
class Solution {
public:
    vector nextGreaterElements(vector& nums) {
        int n = nums.size();
        vector res(n, -1);//初始化全部是-1
        stack st;
        for (int i = 0; i < 2 * n; ++i) {//循环2倍
            int num = nums[i % n];//使用取模运算找到当i大于n时的对应位置
            while (!st.empty() && nums[st.top()] < num) {
                res[st.top()] = num; st.pop();//找到当前下标的下一个最大值就更新res
            }
            if (i < n) st.push(i);
        }
        return res;
    }
};


leetcode提供的解法:
(1)暴力递归
首先将原数组复制一份,然后从第一个数开始,针对每个数往后遍历找到第一个大于他的数。时间复杂度 n方
public class Solution {

    public int[] nextGreaterElements(int[] nums) {
        int[] res = new int[nums.length];
        int[] doublenums = new int[nums.length * 2];
        System.arraycopy(nums, 0, doublenums, 0, nums.length);
        System.arraycopy(nums, 0, doublenums, nums.length, nums.length);
        for (int i = 0; i < nums.length; i++) {
            res[i]=-1;
            for (int j = i + 1; j < doublenums.length; j++) {
                if (doublenums[j] > doublenums[i]) {
                    res[i] = doublenums[j];
                    break;
                }
            }
        }
        return res;
    }
}
(2)暴力递归更新版本,上述方法有无用功,因为每一个数的下一个大于他的数是在除去他之后的后面n-1个数中寻找的。所以第二层循环最多只需遍历n-1个数。

而且不需要将原来的数组扩大,通过使用模运算就可定位到大于数组长度的位置折返到环状前的数,这个和循环队列是一样的道理。
时间复杂度n方,空间复杂度n

public class Solution {
    public int[] nextGreaterElements(int[] nums) {
        int[] res = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            res[i] = -1;
            for (int j = 1; j < nums.length; j++) {
                if (nums[(i + j) % nums.length] > nums[i]) {//通过使用取模运算,将大于数组长度的值折返到前面的位置
                    res[i] = nums[(i + j) % nums.length];
                    break;
                }
            }
        }
        return res;
    }
}

(3)使用栈的方法 比较难理解
https://leetcode.com/problems/next-greater-element-ii/solution/

556. Next Greater Element III

给定一个32位的数,找到一个数和这个数的各位数字相同,只是顺序不一样,这个数是第一个大于原来数的那个,如果不存在,就返回-1
这个题和next permutation思路完全一样  http://blog.csdn.net/m0_37693059/article/details/76304045#t1
需要注意溢出问题
class Solution {
public:
    int nextGreaterElement(int m) {
        string nums=to_string(m);
        int n=nums.size();
        if(n<=1) return -1;
        int left=n-1;
        int right=n-1;
        int posMin=n-1;
        while(left>0&&nums[left]<=nums[left-1])
        {
         left--;
        }
        if(left==0)//如果当前数是最大数
        {
            return -1;
        }
        while(nums[right]<=nums[left-1])
            right--;
        swap(nums[right],nums[left-1]);
        doReverse(nums,left,n-1);
        long long res=stoll(nums);
        return res>numeric_limits::max()?-1:res;   //有可能超过32位数
    }
    void doReverse(string& nums,int left,int right){
        while(left


你可能感兴趣的:(next greater element 系列)