LeetCode每日十题---栈(难度:中等)

题目描述1

在这里插入图片描述

笔者解答1.1

class Solution {
    
    
    public String shortestPalindrome(String s) {
    
    
       int length=s.length();
       for(int i=length-1;i>=0;i--)
       {
    
    
           for(int j=0;j<=i/2;j++)
           {
    
    
               if(s.charAt(j)!=s.charAt(i-j))
               {
    
    
                   break;
               }
               if(j==i/2)
               {
    
    
                   int n=2*s.length()-1-i;
                   char[] str=new char[n];
                   int k;
                   for(k=0;k<length-1-i;k++)
                   {
    
    
                       str[k]=s.charAt(length-k-1);
                       str[n-k-1]=s.charAt(length-k-1);
                   }
                   for(k=length-1-i;k<n;k++)
                   {
    
    
                       str[k]=s.charAt(k-length+1+i);
                   }
                   return String.valueOf(str);
               }
           }
       }
         return ""; 
    }
}

笔者分析1.2

虽然自我感觉还是挺巧妙的,但有些条件下超时了,我的想法是,不断从原字符串末尾删除字符,直到剩余字符满足中心对称,然后再在头部加上被删除的字符拼接成新的字符,但缺点就是时间消耗太长了,之得到评论区向大佬求助,字符串哈希是真的牛!在该方法中,我们将字符串看成一个base进制的数,它对应的十进制就是哈希值。显然,两个字符串的哈希值相等,当且仅当这两个字符串本身相同,然而如果字符传本身很长,其对应的十进制在大多数语言中无法使用内置的整数类型进行存储。因此,我们会将十进制对一个大质数mod进行取摸。
一般来说,我们选取一个大于字符集大小(即字符串中可能出现的字符种类的数目)的质数作为base,再选取一个字符串长度平方级别左右的质数作为mod,产生哈希碰撞的概率就会很低。
算法
一个字符串是回文串,当且仅当该字符串与它的反序相同。因此,我们仍然暴力地美剧s的结束位置,并计算s与s反序的哈希值。如果这两个哈希值相等,说明我们找到了一个s的前缀回文串。设当前枚举到的结束位置为i,对应的s记为si,其反序记为si+.我们可以通过地推的方式,在O(1)的时间内通过s(i-1)和s(i-1)+的哈希只得到si和si+的哈希值:
hash(si)=hash(s(i-1)*base+ASCII(si[i])
hash(si+)=hash(s(i-1)+)+ASCII(s[i])*base;

class Solution {
    
    
    public String shortestPalindrome(String s) {
    
    
        int n = s.length();
        int base = 131, mod = 1000000007;
        int left = 0, right = 0, mul = 1;
        int best = -1;
        for (int i = 0; i < n; ++i) {
    
    
            left = (int) (((long) left * base + s.charAt(i)) % mod);
            right = (int) ((right + (long) mul * s.charAt(i)) % mod);
            if (left == right) {
    
    
                best = i;
            }
            mul = (int) ((long) mul * base % mod);
        }
        String add = (best == n - 1 ? "" : s.substring(best + 1));
        StringBuffer ans = new StringBuffer(add).reverse();
        ans.append(s);
        return ans.toString();
    }
}

题目描述2

在这里插入图片描述

笔者解答2.1

class Solution {
    
    
    public List<Integer> inorderTraversal(TreeNode root) {
    
    
    List<Integer> list=new ArrayList<Integer>();
    inOrder(root,list);
    return list;
    } 
    public static void inOrder(TreeNode root,List<Integer> list)
    {
    
    
        if(root!=null)
        {
    
    
        if(root.left!=null)
        inOrder(root.left,list);
        list.add(root.val);
        if(root.right!=null)
        inOrder(root.right,list);
        }
    }
}

笔者分析2.2

呃,,题目说了用迭代的,忘了。递归的话也太简单了,所以这里着重介绍一下迭代,听巧妙的。只用一个栈就能完成二叉树的中序遍历。

class Solution {
    
    
        public List<Integer> inorderTraversal(TreeNode root) {
    
    
            List<Integer> list = new ArrayList<>();
            Stack<TreeNode> stack = new Stack<>();
            TreeNode cur = root;
            while (cur != null || !stack.isEmpty()) {
    
    
                if (cur != null) {
    
    
                    stack.push(cur);
                    cur = cur.left;
                } else {
    
    
                    cur = stack.pop();
                    list.add(cur.val);
                    cur = cur.right;
                }
            }
            return list;
        }
    }

题目描述3

在这里插入图片描述

笔者分析3.1

这么说吧,我没看懂题目意思。。。但看了下评论区的解答,手法之巧妙,让我即使没写出来,也想把这种手法记录下来。不是我说,栈这一数据结构也太牛逼了吧,以前还没怎么看重它,现在后悔了。二叉搜索树太适合用栈了。

class BSTIterator {
    
    
    private Stack<TreeNode> stack;
    public BSTIterator(TreeNode root) {
    
    
      stack=new Stack<>();
      while(root!=null)
      {
    
    
          stack.push(root);
          root=root.left;
      }
    }
    
    /** @return the next smallest number */
    public int next() {
    
    
      TreeNode node=stack.pop();
      int result=node.val;
      if(node.right!=null){
    
    
          node=node.right;
          while(node!=null){
    
    
              stack.push(node);
              node=node.left;
          }
      }
      return result;
    }
    
    /** @return whether we have a next smallest number */
    public boolean hasNext() {
    
    
       if(stack.empty())
       {
    
    
           return false;
       }
       return true;
    }
}

题目描述4

在这里插入图片描述

笔者解答4.1

class Solution {
    
    
    public boolean isValidSerialization(String preorder) {
    
    
          Stack<String> stack=new Stack<String>();
          List<String> list=new ArrayList<String>();
          list=get_String(preorder);
          if(list==null||(list.get(0).equals("#")&&list.size()==1))
          return true;
          for(int i=0;i<list.size();i++){
    
    
              String str=list.get(i);
              if((i!=0&&stack.isEmpty())||(i==0&&str.equals("#")))
               return false;
              if(str.equals("#"))
             {
    
    
               while(stack.peek().equals("#")&&str.equals("#"))
              {
    
    
                stack.pop();
                stack.pop();
                str="#";
                if(stack.isEmpty())break;
              }
              if(!stack.isEmpty())
              stack.push("#");
             }
              else 
              stack.push(str);            
          }
          if(stack.isEmpty())
          return true;
          return false;
    }
    public static List<String> get_String(String preorder){
    
    
        List<String> list=new ArrayList<String>();
        int getlength=0;
        int last_position=0;
        for(int i=0;i<preorder.length();i++){
    
    
             if(preorder.charAt(i)!=',')
             {
    
    
                 getlength++;
             }
             else
             {
    
    
                 list.add(preorder.substring(last_position,last_position+getlength));
                 getlength=0;
                 last_position=i+1;
             }
        }
         list.add(preorder.substring(last_position,last_position+getlength));
        return list;
    }
}

笔者分析4.2

思路感觉并不复杂,只不过有好多细节没注意到,经过不断调试,虽然最后通过了,但代码也就成了上面那副鬼样。我的思路是如果是数字则直接存入,如果连入两个#则将栈内数据弹出两个(必定是一个#,一个数字),再存入一个#,这里需要一个while循环,因为可能会有多米诺骨牌现象。最后若栈空则该二叉树成立,补充一些题目要求正确的格式就行了。但看到大佬们只用了几行代码就解决了,瞬间脸黑,原来题目还可以这样抽象的写。
迭代:我们可以定义一个概念,叫做槽位,二叉树中任意一个及诶单或者空孩子及诶单都要占据一个槽位。二叉树的建立也伴随这槽位数量的变化。开始时只有一个槽位,如果根节点是空节点,就只消耗掉一个槽位,如果根节点不是空节点,除了消耗一个槽位,还要为孩子节点增加两个新的槽位。之后的节点也是同理。
有了上面的讨论,方法就很简单了。依次遍历前序序列化,根据节点是否为空,按照规则消耗、增加槽位。如果最后可以将所有的槽位消耗完,那么这个前序序列化就是合法的。代码如下。

class Solution {
    
    
  public boolean isValidSerialization(String preorder) {
    
    
    // number of available slots
    int slots = 1;

    for(String node : preorder.split(",")) {
    
    
      // one node takes one slot
      --slots;

      // no more slots available
      if (slots < 0) return false;

      // non-empty node creates two children slots
      if (!node.equals("#")) slots += 2;
    }

    // all slots should be used up
    return slots == 0;
  }
}

总结

今天写的题目类型比较少,虽然写了十题,但比较有特点的也就这几题而已,每日十题打卡第二天,以下图为证。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Achenming1314/article/details/108290988