Leetcode练习题:栈、队列

42:接雨水

问题描述

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

源自leectcode官网

上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图,图源自LeetCode官网。

示例:

输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6

解题思路

首先想到暴力解决该问题,只需要在每个位置,找到左边界和右边界,即左右两部分中最高的部分,选择较小值再与该位置高度计算即可。

学习了使用栈的解法:
只有低洼处才能积水。从左往右开始遍历高度,
如果低于当前栈顶高度,则没有形成低洼,继续。
如果高于当前栈顶高度,则形成了低洼,进行一次计算。将栈顶元素pop,记为bottom,pop后的栈顶元素为左边界,当前元素为右边界,水洼宽度为左右边界的距离,积水高度跟暴力解法一样。
注意栈里的元素是index,不是高度

代码实现

暴力代码

int trap(vector<int>& height)

{

             //填充本函数完成功能
             int ans=0;
             for(int i=1;i<height.size()-1;i++)
             {
                 int left=0,right=0;
                 for(int j=i;j>=0;j--)
                 {
                     left=max(left,height[j]);
                 }
                 for(int j=i;j<height.size();j++)
                 {
                     right=max(right,height[j]);
                 }
                 ans+=min(left,right)-height[i];
             }
             return ans;

}

int trap(vector<int>& height)
{
    int ans = 0, current = 0;
    stack<int> st;
    while (current < height.size()) {
        while (!st.empty() && height[current] > height[st.top()]) {
            int bottom = st.top();
            st.pop();
            if (st.empty())
                break;
            int distance = current - st.top() - 1;
            int bounded_height = min(height[current], height[st.top()]) - height[bottom];
            ans += distance * bounded_height;
        }
        st.push(current++);
    }
    return ans;
}

反思与收获

这题实现有很多种办法,除了暴力能想出来,其他都不行。尽管知道是使用栈的知识,但是实际应用起来还是有一点困难。不过理解题目的时候按照“如果我人工来解会怎么做”一步步推理来,或许会有帮助。

71:简化路径

问题描述

以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。

在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (…) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。更多信息请参阅:Linux / Unix中的绝对路径 vs 相对路径

请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。

示例 1:

输入:"/home/"

输出:"/home"

解释:注意,最后一个目录名后面没有斜杠。

示例 2:

输入:"/…/"

输出:"/"

解释:从根目录向上一级是不可行的,因为根是你可以到达的最高级。

示例 3:

输入:"/home//foo/"

输出:"/home/foo"

解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。

示例 4:

输入:"/a/./b/…/…/c/"

输出:"/c"

示例 5:

输入:"/a/…/…/b/…/c//.//"

输出:"/c"

示例 6:

输入:"/a//bc/d//././/…"

输出:"/a/b/c"

解题思路

这题实质上是一个字符串分割的问题,需要用到栈仅仅是…需要返回上一级,要先进行栈是否为空的判断,以及最后答案需要判断是否添加’/’
将路径以’/‘进行分割,
如果字符串为空或者为’.‘或者为’…‘但栈为空,则继续
如果为’…'栈不为空,则pop
否则push

代码实现

vector<string> func(string str,char split)
{
    vector<string> tokens;
    string temp;
    istringstream ss(str);
    while(getline(ss,temp,split))
    {
        if(temp==""||temp=="."||(temp==".."&&tokens.size()==0))
        {
            continue;
        }else if(temp==".."&&tokens.size()>0)
        {
            tokens.pop_back();
        }else
        {
            tokens.push_back(temp);
        }
    }
    return tokens;
}

string path(string str)
{
    string ans="";
    vector<string> s=func(str,'/');
    for(auto i:s)
    {
        ans+='/';
        ans+=i;
    }
    return ans==""?"/":ans;
}

反思与收获

在c++中我经常是使用istringstream来实现字符串分割的,还能按指定的字符进行分割,在很多题目中都会运用到。

getline(ss,temp,split)

如果是按照空格分割,直接使用

string str,temp;
istringstream ss(sr)
ss>>temp;

347:前k个高频元素

问题描述

给定一个非空的整数数组,返回其中出现频率前 k 高的元素。

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2

输出: [1,2]

示例 2:

输入: nums = [1], k = 1

输出: [1]

说明:

你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。

你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。

题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。

输出时,首先输出频率最高的元素,如果频率相同,则先输出元素值较大的元素。

解题思路

首先利用哈希表,对各个元素进行个数统计,这里运用到的栈队列知识为,使用优先队列对其进行排序,意义在于只求前k个高频元素,所以比sort进行快排会稍微高效一点。
尽管如此…我的代码依旧是sort实现

代码实现

sort

    map<int,int> m;
        for(auto i:nums)
        {
            m[i]++;
        }

        vector<pair<int,int>> v;
        vector<int> ans;
        for(auto i:m)
        {
            v.push_back(make_pair(i.second,i.first));
        }
            sort(v.begin(),v.end());
            for(int i=1;i<=k;i++)
            {
                ans.push_back(v[v.size()-i].second);
            }

        return ans;

    }

priority_queue
学习题解

反思与收获

之前没有学习过优先级队列的知识,实际上就是最大堆,最小堆的c++实现,对后续的学习很有帮助,尤其是解决前k个这样子的问题。
关于优先队列的知识可以参考:c++优先队列(priority_queue)用法详解

373:查找和最小的K对数字

问题描述

给定两个以升序排列的整形数组 nums1 和 nums2, 以及一个整数 k。
定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2。
找到和最小的 k 对数字 (u1,v1), (u2,v2) … (uk,vk),按从小到大的顺序输出它们的和。

示例 1:

输入: nums1 = [1,7,11], nums2 = [2,4,6], k = 3

输出: 因为前三对是:[1,2],[1,4],[1,6],所以输出3,5,7

解释: 返回序列中的前 3 对数:

 [1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]

示例 2:

输入: nums1 = [1,1,2], nums2 = [1,2,3], k = 2

输出: 2, 2

解释: 返回序列中的前 2 对数:

 [1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3]

示例 3:

输入: nums1 = [1,2], nums2 = [3], k = 3

输出: 总共只有两对:[1,3],[2,3],所以输出4, 5

解释: 也可能序列中所有的数对都被返回:[1,3],[2,3]

解题思路

将每一种配对情况都进行比较,利用优先级队列。
虽然是前K个小的,但是我建立的最大堆,堆的大小为K
如果小于k,则插入这两个数
如果大于k了,则跟top进行比较,一点点将较大的配对情况挤出去,留下了k个较小的情况。
根据题目输出要求,最后的答案需要倒置。

代码实现

 struct cmp{
        bool operator()(pair<int ,int>&a,pair<int,int>&b)
        {
            return a.first+a.second<b.first+b.second;
        }
    };

    vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
        vector<vector<int>> ans;
        /*优先队列的知识,最大堆最小堆,因为是前k个小的 所以建大堆*/
        priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> q;
        for(int i=0;i<nums1.size();i++)
        {
            for(int j=0;j<nums2.size();j++)
            {
                if(q.size()<k)
                {
                    q.push({nums1[i],nums2[j]});
                }else if(nums1[i]+nums2[j]<q.top().first+q.top().second)
                {
                    q.pop();
                    q.push({nums1[i],nums2[j]});
                }
            }
        }
        while(!q.empty())
        {
            pair<int,int> top=q.top();
            ans.push_back({top.first,top.second});
            q.pop();
        }

        reverse(ans.begin(),ans.end());
        return ans;
    }

反思与收获

关于priority_queue的学习收获,其实感觉有点乱…综合目前看过了博客学习资料。
priority_queue是默认大根堆,对应的是less的函数

priority_queue <int> a;
//相当于
priority_queue<int vector<int>,less<int> >a
//相当于
 struct cmp{
        bool operator()(pair<int ,int>&a,pair<int,int>&b)
        {
            return a.first+a.second<b.first+b.second;
        }
    };
priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> a;

为什么是小于的函数,却是最大堆呢
据说是因为是队尾指向的是堆顶元素,队首指向最后一个元素。
参考资料1
参考资料2

394:字符串解码

问题描述

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

示例 1:

输入:s = “3[a]2[bc]”

输出:“aaabcbc”

示例 2:

输入:s = “3[a2[c]]”

输出:“accaccacc”

示例 3:

输入:s = “2[abc]3[cd]ef”

输出:“abcabccdcdcdef”

示例 4:

输入:s = “abc3[cd]xyz”

输出:“abccdcdcdxyz”

解题思路

有点跟括号配对相关,因此考虑使用栈。
一个数字栈,一个字符串栈
遇见数字,要做将字符串变成数字的操作
遇见字符,则加到ans后面
遇见’[’,添加到对应的栈中,并初始化
遇见’]’,需要进行操作:首先数字栈弹出,作为循环的次数,其次对字符串栈的栈顶进行字符串添加,更新ans,弹出top。
这里需要搞清楚的点是ans并不是temp的作用,而是真正要返回的答案,ans是一层层往外更新的。
字符串栈中的每一个元素,是每一个循环节。

代码实现

string decodeString(string str) {
        string ans,temp,tempans;
        stack<string> s;
        stack<int> n;
        int num=0,t;
        for(int i=0;i<str.length();i++)
        {
            if(str[i]<='9'&&str[i]>='0')
            {
                num=num*10+str[i]-'0';

            }else if(str[i]=='[')
            {
                n.push(num);
                num=0;
                s.push(ans);
                ans="";
            }else if(str[i]<='z'&&str[i]>='a'||(str[i]<='Z'&&str[i]>='A'))
            {
                ans.push_back(str[i]);
            }else{
                t=n.top();
                n.pop();
                for(int i=0;i<t;i++)
                {
                    s.top()+=ans;
                }
                ans=s.top();
                s.pop();
            }
        }
        return ans;
    }

反思与收获

解决类似括号中套用括号的情况,常常是考虑利用栈来实现,或者是递归。对于数字+字符串的处理,可以考虑分别使用各自的栈。但需要想清楚的是,栈中的元素是什么。

407:接雨水Ⅱ

问题描述

给你一个 m x n 的矩阵,其中的值均为非负整数,代表二维高度图每个单元的高度,请计算图中形状最多能接多少体积的雨水。

示例:

给出如下 3x6 的高度图:

[

[1,4,3,1,3,2],

[3,2,1,3,2,4],

[2,3,3,2,3,1]

]

返回 4 。

如下图所示,这是下雨前的高度图[[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]] 的状态。
图源自LeetCode
下雨后,雨水将会被存储在这些方块中。总的接雨水量是4。
图源自LeetCode

说明:

1 <= m, n <= 110

0 <= heightMap[i][j] <= 20000

解题思路

是2维接雨水的升级版,如果使用之前的暴力方法,即找到四个方向的最小再比较,显然时间复杂度会很高。需要换种思路来实现。
并没有想出来,学习了大佬的题解
一开始看完题解之后还有几个需要注意地方:
1.首先这一圈边界的高度是要进行排序的,通过优先级队列实现,因为木桶原理,我们需要最低的边界,即q.top()
2.所谓的考虑一周或者说考虑它周围一圈,如果此元素比周围元素高,则可以灌水,我一开始想成了[[0,0,0],[0,1,0],[0,0,0]]这样的情况,实际上并不是四个方向每一次都计算的,因为要考虑是否visited的情况,其实是每一次只考虑往中心的方向。
写在代码注释中

代码实现

struct node{
        int x,y,h;
        node(int xx,int yy,int hh):x(xx),y(yy),h(hh){};
        bool operator <(const node &n) const{
            return n.h<h;
        }
    };
    int trapRainWater(vector<vector<int> >& heightMap)

    {

             //填充本函数完成功能
        if(heightMap.size()==0||heightMap[0].size()==0)
        {
            return 0;
        }
        int n=heightMap.size();
        int m=heightMap[0].size();

        vector<vector<bool> > visited(n,vector<bool>(m));
        priority_queue<node> q;

        //首先是最外面的一圈
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(i==0||j==0||i==n-1||j==m-1)
                {
                    q.push({i,j,heightMap[i][j]});
                    visited[i][j]=true;
                }
            }
        }

        int ans=0;
        //这个方向一维函数很强可以学
        int dirc[]={-1,0,1,0,-1};
        
        while(!q.empty())
        {
            node c=q.top();
            q.pop();
            for(int i=0;i<4;i++)
            {
                int xx=c.x+dirc[i];
                int yy=c.y+dirc[i+1];
                //不断往里缩,在上边界的只能往下走,因为左右上都visited了
                if(xx>=0&&xx<n&&yy>=0&&yy<m&&!visited[xx][yy])
                {
                    //因此如果该边界大于当前考虑的元素高度,则可以灌水
                    if(c.h>heightMap[xx][yy])
                    {
                        ans+=c.h-heightMap[xx][yy];
                    }
                    //高度更新为最高的那一个
                    q.push({xx,yy,max(c.h,heightMap[xx][yy])});
                    visited[xx][yy]=true;
                }
            }
        }
        return ans;
    }

反思与收获

用一维数组表示二维的方向

        int dirc[]={-1,0,1,0,-1};

大佬实在是太强了,我实在是太菜了…

621:任务调度器

问题描述

给定一个用字符数组表示的 CPU 需要执行的任务列表。其中包含使用大写的 A - Z 字母表示的26 种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。CPU 在任何一个单位时间内都可以执行一个任务,或者在待命状态。

然而,两个相同种类的任务之间必须有长度为 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。

你需要计算完成所有任务所需要的最短时间。

示例 :

输入:tasks = [“A”,“A”,“A”,“B”,“B”,“B”], n = 2

输出:8

解释:A -> B -> (待命) -> A -> B -> (待命) -> A -> B.

在本示例中,两个相同类型任务之间必须间隔长度为 n = 2 的冷却时间,而执行一个任务只需要一个单位时间,所以中间出现了(待命)状态。

解题思路

出现次数越多的任务越先执行,这样才能更大程度上的避免相同任务的出现浪费时间。
排序,每一次按出现次数进行排序,每轮最多选取n+1个任务。
优先级队列,使用最大堆,每一轮最多选择n+1个任务,次数-1后再重新放入堆中。
两种方法时间空间复杂度一样。T(n)=O(time) O(n)=O(1)

代码实现

排序:

  int leastInterval(vector<char>& tasks, int n) {
        int t[26]={0};
        for(auto i:tasks)
        {
            t[i-'A']++;
        }

        sort(t,t+26);
        int time=0;
        while(t[25]>0)
        {
            int i=0;
            while(i<=n)
            {
                if(t[25]==0)
                {
                    break;
                }
                if(i<26&&t[25-i]>0)
                {
                    t[25-i]--;
                }
                time++;
                i++;
            }
            sort(t,t+26);
        }
         return time;
    }

优先级队列

 int leastInterval(vector<char>& tasks, int n) {
        int t[26]={0};
        for(auto i:tasks)
        {
            t[i-'A']++;
        }

        priority_queue<int> q;

        for(int i=0;i<26;i++)
        {
            if(t[i]>0)
            {
                q.push(t[i]);
            }

        }


        int time=0;
        while(!q.empty())
        {
            int i=0;
            vector<int> temp;
            while(i<=n)
            {
                if(!q.empty())
                {
                    if(q.top()>1)
                    {
                        temp.push_back(q.top()-1);
                        q.pop();
                    }
                    else
                    {
                        q.pop();
                    }
                }
                time++;
                if(q.empty()&&temp.empty())
                {
                    break;
                }

                i++;
            }
            for(int i=0;i<temp.size();i++)
            {
                q.push(temp[i]);
            }

        }
         return time;
    }

反思与收获

使用排序的时候考虑的是26个数字(包括0),使用优先级队列时候只考虑了大于0的数字,因此判断的代码上面会有一些不同,要学会两者之间转换,熟练使用。

862:和至少为K的最短子数组

问题描述

返回 A 的最短的非空连续子数组的长度,该子数组的和至少为 K 。

如果没有和至少为 K 的非空子数组,返回 -1 。

示例 1:

输入:A = [1], K = 1

输出:1

示例 2:

输入:A = [1,2], K = 4

输出:-1

示例 3:

输入:A = [2,-1,2], K = 3

输出:3

说明:

1 <= A.length <= 50000

-10 ^ 5 <= A[i] <= 10 ^ 5

1 <= K <= 10 ^ 9

解题思路

参考了大佬的题解选择了第三种方法双端队列。
在遇到连续子数组/子序列之和这样子的问题时,通常考虑使用前缀和来解决。但由于这个数组中有正有负,因此不是单调递增的情况,但仍可以使用单调栈。原因是:
如果单调序列的和大于等于K,则非单调序列的和一定小于单调序列的和(很好理解,不增或减),并且非单调序列的长度一定大于单调序列(相当于中间有几个捣乱的)
比如
序列: 2 -1 2 3
前缀和: 2 1 3 6
单调栈:1 3 6
6和1的差值一定是大于6和2的,并且6到1的长度小于6到2,因此2省略

因为是单调栈,因此当前元素减去栈底元素的差值是最大的,比较差值与K的大小关系即可,记录长度,并将栈底元素pop(如果不pop,后来的元素更大,肯定更加符合大于等于K,长度也会更长,所以pop就行了)

代码实现

int shortestSubarray(vector<int>& A, int K) {
//注意要先插入初始化的前缀和0
        A.insert(A.begin(),0);
        vector<int> sum=vector<int>(A.size(),0);
        //双端队列 两头都可以操作进队出队
        //需要计算长度,因此记录的是index
        deque<int> temp;
        int len=INT_MAX;

        //sum[i]=A[0]+A[1]+...+A[i]
        for(int i=0;i<sum.size();i++)
        {
            if(i==0)
            {
                sum[i]=A[i];
            }else{
                sum[i]=sum[i-1]+A[i];
            }
        }

        for(int i=0;i<sum.size();i++)
        {
            //保持单调栈,如果栈顶元素大于当前元素则pop
            while(!temp.empty()&&sum[i]<sum[temp.front()])
            {
                temp.pop_front();
            }
            //与栈底元素做差值比较
            while(!temp.empty()&&sum[i]-sum[temp.back()]>=K)
            {
                len=min(len,i-temp.back());
                temp.pop_back();
            }
            temp.push_front(i);
        }
        return len==INT_MAX?-1:len;
    }

反思与收获

前缀和这个概念学习到了,经常在求和甚至是求差的时候用到。
双向队列便于在队首和队尾进行操作,处理某些问题十分方便。
(看LeetCode的官网题解,这似乎也可以叫做“滑动窗口”?)

921:使括号有效的最少添加

问题描述

给定一个由 ‘(’ 和 ‘)’ 括号组成的字符串 S,我们需要添加最少的括号( ‘(’ 或是 ‘)’,可以在任何位置),以使得到的括号字符串有效。

从形式上讲,只有满足下面几点之一,括号字符串才是有效的:

它是一个空字符串,或者

它可以被写成 AB (A 与 B 连接), 其中 A 和 B 都是有效字符串,或者

它可以被写作 (A),其中 A 是有效字符串。

给定一个括号字符串,返回为使结果字符串有效而必须添加的最少括号数。

示例 1:

入:"())"

输出:1

示例 2:

输入:"((("

输出:3

示例 3:

输入:"()"

输出:0

示例 4:

输入:"()))(("

输出:4

说明:
S.length <= 1000
S 只包含 ‘(’ 和 ‘)’ 字符。

解题思路

这题比较简单,就是括号配对的问题,使用栈来解决,只需要求添加括号的数量,不需要知道在哪添加,因此答案就是栈最后的大小

代码实现

int main()
{
    string str;
    getline(cin,str);
    stack<char> s;
    for(int i=0;i<str.length();i++)
    {
        if(!s.empty()&&s.top()=='('&&str[i]==')')
        {
            s.pop();
        }
        else
        {
            s.push(str[i]);
        }
    }
    cout<<s.size();
}

反思与收获

对于简单的题目,想想办法尽量将代码写的简洁。

1190:反转每对括号间的子串

问题描述

给出一个字符串 s(仅含有小写英文字母和括号)。

请你按照从括号内到外的顺序,逐层反转每对匹配括号中的字符串,并返回最终的结果。

注意,您的结果中不应 包含任何括号。

示例 1:

输入:s = “(abcd)”

输出:“dcba”

示例 2:

输入:s = “(u(love)i)”

输出:“iloveu”

示例 3:

输入:s = “(ed(et(oc))el)”

输出:“leetcode”

示例 4:

输入:s = “a(bcdefghijkl(mno)p)q”

输出:“apmnolkjihgfedcbq”

说明:

0 <= s.length <= 2000

s 中只有小写英文字母和括号

我们确保所有括号都是成对出现的

解题思路

建立一个字符串栈来存放被括号分割的各个字符。
遇见‘(’:将前面扫描的字符串放入栈中,ans清空
遇见’)’:将从’(‘扫描至’)'的字符串倒置,并添加到栈顶元素后面,更新ans
遇见其他字符:添加至ans后面

代码实现

int main()
{
    string str;
    getline(cin,str);

    string ans;
    stack<string> s;
    for(int i=0;i<str.length();i++)
    {
        if(str[i]=='(')
        {
            s.push(ans);
            ans="";
        }else if(str[i]==')')
        {
            reverse(ans.begin(),ans.end());
            ans=s.top()+ans;
            s.pop();
        }else
        {
            ans.push_back(str[i]);
        }
    }
    cout<<ans;
}

反思与收获

这题跟394字符串解码有点相似,学会ans的用法,字符串栈的创建。

1439:有序矩阵中的第 k 个最小数组和

问题描述

给你一个 m * n 的矩阵 mat,以及一个整数 k ,矩阵中的每一行都以非递减的顺序排列。

你可以从每一行中选出 1 个元素形成一个数组。返回所有可能数组中的第 k 个 最小 数组和。

示例 1:

输入:mat = [[1,3,11],[2,4,6]], k = 5

输出:7

解释:从每一行中选出一个元素,前 k 个和最小的数组分别是:

[1,2], [1,4], [3,2], [3,4], [1,6]。其中第 5 个的和是 7 。

示例 2:

输入:mat = [[1,3,11],[2,4,6]], k = 9

输出:17

示例 3:

输入:mat = [[1,10,10],[1,4,5],[2,3,6]], k = 7

输出:9

解释:从每一行中选出一个元素,前 k 个和最小的数组分别是:

[1,1,2], [1,1,3], [1,4,2], [1,4,3], [1,1,6], [1,5,2], [1,5,3]。其中第 7
个的和是 9 。

示例 4:

输入:mat = [[1,1,10],[2,2,9]], k = 7

输出:12

说明:

m ,n为矩阵 mat的行列数

1 <= m, n <= 40

1 <= k <= min(200, n ^ m)

1 <= mat[i][j] <= 5000

mat[i] 是一个非递减数组

解题思路

或许是要我们用优先级队列的知识来解决,但是暴力就可以解决。
学习了一些题解,暴力解决的重点在于,每次我们是一行一行来添加考虑,每次只保留前K个答案,再进行下一行的添加。

代码实现

int kthSmallest(vector<vector<int>>& mat, int k) {
        //首先添加第一行
        vector<int> ans(mat[0]);
        for(int i=1;i<mat.size();i++)
        {
            //学到新的容器ultiset支持重复 还默认排序
            multiset<int> s;
            //与下一行进行配对添加
            for(int j=0;j<ans.size();j++)
            {
                for(int k=0;k<mat[i].size();k++)
                {
                    s.insert(ans[j]+mat[i][k]);
                }
            }
            //学到assign的用法赋值
            ans.assign(s.begin(),s.end());
            //只保留K个,或者列数个
            ans.resize(min(k,(int)ans.size()));
        }
        return ans.back();
    }

反思与收获

vector assign用法:

void assign(const_iterator first,const_iterator last);
将区间[first,last)的元素赋值到当前的vector容器中
void assign(size_type n,const T& x =T());
将n个值为x的元素赋值到vector容器中 注:会清除掉vector容器中以前的内容。

vector resize用法:

改变vector中元素的数目。

如果n比当前的vector元素数目要小,vector的容量要缩减到n。并销毁超出n的元素。

如果n比当前vector元素数目要大,在vector的末尾扩展需要的元素数目,如果第二个参数val指定了,扩展的新元素初始化为val的副本,否则按类型默认初始化。

——————————————————————
自己写的代码,过一段时间就看不懂了…每次归纳整理写起来,仿佛都重新做了一遍,温故而知新啊ヾ(◍°∇°◍)ノ゙

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值