题目描述1
笔者解答1.1
class Solution {
public String removeKdigits(String num, int k) {
Stack<Character> stack=new Stack<Character>();
stack.push(num.charAt(0));
for(int i=1;i<num.length();i++){
char last=stack.peek();
char c=num.charAt(i);
while(c<last&&k>=1)
{
last=stack.pop();
k--;
}
stack.push(c);
}
char[] str=new char[num.length()];
int length=0;
while(!stack.isEmpty()){
str[length]=stack.pop();
length++;
}
String str2="";
boolean getfirst_notzero=false;
for(int i=length-1;i>=k;i--){
if(getfirst_notzero||str[i]!='0'){
str2+=""+str[i];
getfirst_notzero=true;
}
}
if(str2.equals(""))
return "0";
return str2;
}
}
笔者分析1.2
这题思路挺简单的,但我写的代码还有写用例过不去,很难受。看了下评论区解答,发现思路都差不多,但他们的方法和代码量明显会简洁好多。思路就是,从左到右,找第一个比后面大的字符,删除,清零,k次扫描,代码如下。
class Solution {
public String removeKdigits(String num, int k) {
if (num.length() == k) return "0";
StringBuilder s = new StringBuilder(num);
for (int i = 0; i < k; i++) {
int idx = 0;
for (int j = 1; j < s.length() && s.charAt(j) >= s.charAt(j - 1); j++) idx = j;
s.delete(idx, idx + 1);
while (s.length() > 1 && s.charAt(0) == '0') s.delete(0, 1);
}
return s.toString();
}
}
题目描述2
笔者解答2.1
class Solution {
public boolean find132pattern(int[] nums) {
for(int i=0;i<nums.length-2;i++){
int a=nums[i];
for(int j=i+1;j<nums.length-1;j++){
int b=nums[j];
if(b>a){
for(int k=j+1;k<nums.length;k++){
int c=nums[k];
if(c<b&&c>a)
return true;
}
}
}
}
return false;
}
}
笔者分析2.2
挺有意思的一道题目,上面是我的最初想法,很明显时间超时了,待我再想想。。。好吧,我是废物!
大佬思路:我们首先考虑啊a[i]<a[j]的部分。当我们固定了j时,我们可以再j的左侧找出一个最小的数作为a[i],这是因为最终我们需要满足a[i]<a[k]<a[j],那么a[i]一定越小越好。因此我们可以对数组a维护前缀最小值,即min[j]=min(a[1…j]),这样对于一个固定的j,min[j]即为最优的a[i]。
随后我们再考虑a[k],其中a[k]需要满足a[i]<a[k]<a[j],即min[j]<a[k]<a[j]。我们可以从数组a的末尾开始,从后向前寻找a[k]。
我们可以用栈来存储所有的a[k]。再栈中,所有候选的a[k]保持降序,即栈顶的元素最小,栈底的元素最大。即如果我们遇到一个新的a[k],那么我们会将栈定的元素依次出栈,直到新的a[k]为栈中的最小元素。我们在从右向左便利数组a时,假设我们当前位于a[j],首先我们判断是否右nums[j]>min[j],如果不成立,那么我们要跳过这个a[j],否则我们将栈顶的元素依次出栈,直到栈顶元素stack[top]满足stack[top]>min[j]。在这之后,我们可以确定栈中的所有元素都大于min[j]因此如果此时栈顶的元素和j可以满足132模式,那么我们就找到了一组合法的满足132模式的i,j,k,否则我们继续寻找,此时需要吧a[j]入栈。如果在便利结束后,我们仍然没有找到满足132模式的i,j,k,那么我们需要返回False。代码如下
public class Solution {
public boolean find132pattern(int[] nums) {
if (nums.length < 3)
return false;
Stack < Integer > stack = new Stack < > ();
int[] min = new int[nums.length];
min[0] = nums[0];
for (int i = 1; i < nums.length; i++)
min[i] = Math.min(min[i - 1], nums[i]);
for (int j = nums.length - 1; j >= 0; j--) {
if (nums[j] > min[j]) {
while (!stack.isEmpty() && stack.peek() <= min[j])
stack.pop();
if (!stack.isEmpty() && stack.peek() < nums[j])
return true;
stack.push(nums[j]);
}
}
return false;
}
}
题目描述3
笔者解答3.1
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
Stack<Integer> stack=new Stack<Integer>();
for(int i=0,j=0;i<pushed.length;i++){
stack.push(pushed[i]);
while(stack.peek()==popped[j]){
stack.pop();j++;
if(stack.isEmpty())break;
}
}
if(!stack.isEmpty())
return false;
return true;
}
}
笔者分析3.2
这题虽然没啥难度,但个人认为还是比较典型的。主要思路是,遍历pushed序列,如果何popped序列中的元素值相等,则在pushed序列中弹出该元素,这里是个While循环。直到对应元素不等,则将pushed序列i+1至下一个元素。最后若栈为空则返回true,否则false。
题目描述4
笔者解答4.1
class Solution {
public int[] nextGreaterElements(int[] nums) {
int[] str=new int[nums.length];
for(int i=0;i<nums.length;i++){
int a=nums[i];
int j;
for(j=(i+1)%nums.length;j!=i;j=(j+1)%nums.length){
if(nums[j]>a)
{
str[i]=nums[j];break;
}
}
if(j==i)str[i]=-1;
}
return str;
}
}
笔者分析4.2
说来惭愧,看到这题我的第一反应还是用两个for循环,执行用时击败了0.05的用户。丢人啊,只好再去评论区学习一下大佬们的方法。
单调栈:我们首先把第一个元素A[1]放入栈,随后对于第二个元素A[2],如果A[2]>A[1],那么我们就找到了A[1]的下一个更大元素A[2],此时就可以把A[1]出栈并把A[2]入栈;如果A[2]<=A[1],我们就仅把A[2]入栈。对于第三个元素A[3],此时栈中有若干个元素,那么所有比A[3]小的元素都找到了下一个更大的元素(即A[3]),因此可以出栈,在这之后,我们将A[3]入栈,以此类推。代码如下:
class Solution {
public int[] nextGreaterElements(int[] nums) {
int n = nums.length;
int [] res = new int[n];
Arrays.fill(res, -1);
Stack <Integer> stack = new Stack<>();
for (int i = 0; i < n*2; i++){
int num = nums[i % n];
while(!stack.isEmpty() && num > nums[stack.peek()]){
res[stack.pop()] = num;
}
if(i < n) stack.add(i);
}
return res;
}
}
题目描述5
笔者解答5.1
class Solution {
public int[] asteroidCollision(int[] asteroids) {
Stack<Integer> stack=new Stack<Integer>();
int[] str=new int[asteroids.length];
int count=0;
int count_stack=0;
for(int i=0;i<asteroids.length;i++){
int temp=asteroids[i];
while(!stack.isEmpty()){
if(temp<0)
{
if(stack.peek()>0-temp){
temp=0;
break;
}else if(stack.peek()==0-temp)
{
stack.pop();
count_stack--;
temp=0;break;
}
else
{
stack.pop();
count_stack--;
}
}
else{
stack.push(temp);temp=0;
count_stack++;break;
}
}
if(stack.isEmpty()&&temp>0)
{
stack.push(temp);
count_stack++;
}
if(temp<0)
{
str[count]=temp;
count++;
}
}
int[] strout=new int[count+count_stack];
for(int i=0;i<count;i++)
strout[i]=str[i];
while(!stack.isEmpty()){
strout[count+count_stack-1]=stack.pop();
count_stack--;
}
return strout;
}
}
笔者分析5.2
总体来说还是挺简单的,像我这种菜鸡都能一遍过。主要还是围绕栈来展开的,如果开始进入的为负数,那么直接将它存入最后的结果当中,因为它不肯能爆炸,追不上,遍历到第一个正数时,将其入栈。若接下来遇到的都是正数,也直接入站,若为负数,则比较绝对值大小,按情况分析,这里是一个while循环,因为一个大的负数,能把栈内路过的小正数都给炸没了,而不是只炸一次,若炸完了栈中所有正数,负数还存活的话,就相当于一开始进入的为负数,那么这时就要将其存入最后的结果当中,不必入栈。遍历完之后,栈要么为空,要么全是正数,谁都追不上谁,最后结果要加上这剩余栈中的正数。这里有个小问题,返回的数组大小要和它包含有效数据的个数一致,空间不能开大了,否则会自动用0填充。
题目描述6
笔者解答6.1
class Solution {
public int[] dailyTemperatures(int[] T) {
Stack<Integer> stack=new Stack<Integer>();
Stack<Integer> stack_id=new Stack<Integer>();
int[] str=new int[T.length];
stack.push(T[0]);
stack_id.push(0);
for(int i=1;i<T.length;i++){
while(!stack.isEmpty()&&T[i]>stack.peek()){
stack.pop();
int id=stack_id.pop();
str[id]=i-id;
}
stack.push(T[i]);
stack_id.push(i);
if(T[i]<=stack.peek()){
stack.push(T[i]);
stack_id.push(i);
}
}
while(!stack_id.isEmpty()){
int id=stack_id.pop();
str[id]=0;
}
return str;
}
}
笔者分析6.2
好像是和上面找下一个最大元素题是一样的,用的是单调栈,具体就不重复介绍了。
总结
有点意思,至少可以在自己的代码里找到算法的感觉了,每日十题打卡第三天,以下图为证。