思路:
题目的主要信息:
- n个人的身高用数组a表示
- 每个人往前面开枪,会打到他前面比他高的第一个人,同时荒唐度增加被打到这个人的次序号(下标+1)
- 求最后总的荒唐度
- 方法一:暴力解法*
- 具体做法:*
遍历数组每个人,然后每次往这个前面找到第一个大于它的元素,返回值增加下标加1.class Solution { public: long long solve(int n, vector<int>& a) { long long res = 0; for(int i = 1; i < n; i++){ int j = i - 1; //往前 while(j >= 0 && a[j] <= a[i]) //往前找到第一个大于i的j j--; res += j + 1; //下标数加1 } return res; } };
复杂度分析:
- 时间复杂度:,最坏情况的是第一个元素最大,后续是递增序列,需要循环两层
- 空间复杂度:,常数级变量空间
方法二:单调栈
具体做法:
使用一个栈保存一个从栈底到栈顶的单调递减序列,同时记录其次序号。遍历的时候需要从a[i]左边找到第一个大于它的元素,我们就可以不断从栈中弹出小于它的然后将其加入栈,因为比它小的都会被它挡住,在后续相当于没用了。
class Solution { public: long long solve(int n, vector<int>& a) { long long res = 0; stack<pair<int, int> > s; //分别记录身高和次序号(下标+1) s.push({a[0], 1}); for(int i = 0; i < n; i++){ while(!s.empty() && s.top().first <= a[i]) //往前找到第一个大于a[i]的 s.pop(); if(!s.empty()) //不为空说明有打到人 res += s.top().second; s.push({a[i], i + 1}); } return res; } };
复杂度分析:
- 时间复杂度:,外循环为,内循环在整个外循环过程中总共访问次数不可能超过数组中长度,故总计最多访问为次
- 空间复杂度:,栈空间最大为