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<int> nextGreaterElement(vector<int>& findNums, vector<int>& nums) {
        map<int,int> inp;
        vector<int> res;
        int n=nums.size();
        stack<int> q;
        for(auto s:nums)
        {
            while(!q.empty()&&q.top()<s)
            {
                inp[q.top()]=s;
                q.pop();
            }
            q.push(s);
        }
        for(auto s:findNums)
        {
            if(inp.find(s)!=inp.end())
                res.push_back(inp[s]);
            else
                res.push_back(-1);
        }
        return res;
    }
};

503. Next Greater Element II

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

上述解法的改进版本:
可以不使用map,预先设定res数组的初始值是-1,每次找到一个最大值就更新res中相应的位置。这里使用了取模运算。
class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        int n = nums.size();
        vector<int> res(n, -1);//初始化全部是-1
        stack<int> 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)使用栈的方法 比较难理解

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<int>::max()?-1:res;   //有可能超过32位数
    }
    void doReverse(string& nums,int left,int right){
        while(left<right)
        {
            int temp=nums[left];
            nums[left++]=nums[right];
            nums[right--]=temp;
        }
    }
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值