next greater element 系列

来源:互联网 发布:莆田鞋怎么在淘宝上找 编辑:程序博客网 时间:2024/06/09 18:11

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)使用栈的方法 比较难理解
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<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;        }    }};


原创粉丝点击