LeetCode 5.Longest Palindromic Substring & 241.Different Ways to Add Parentheses

Problem 5. Longest Palindromic Substring

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.


Example:
Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.

Example:
Input: "cbbd"
Output: "bb"


解题思路:

1. 寻找最长的对称子串,从头开始遍历字符串,可以考虑从子串的中心出发,以当前字符为子串中心,同时向两端延伸,看是否两端的值是否一直相等,延伸到两端的值不相等后,以该字符为中心的对称子串寻找结束,记录长度,然后开始寻找以下一个字符为中心的对称子串。

2.对称的子串长度可能为奇数如“aba",也可能为偶数"abba",这两个情况下确定中心的方法不太一样,需要注意。长度为奇数时只需以当前字符为中心进行延伸,为偶数时,则需要以两个相同且连续的字符开始进行延伸。

代码如下:

public class Solution {
   private int head = 0; 
  private int tail = 0; 
   public String longestPalindrome(String s) {
    int length = s.length();
          
          int i = 0; 
          int j = 0;
          if(length <= 1) return s;
          for(i = 0;i < length;i++){
           
            findPalindrome(s,i,i);
            findPalindrome(s,i,i+1);
          }
          return s.substring(head,tail+1);

}

private void findPalindrome(String s,int i,int j){
   while(i >=0 && j < s.length() && s.charAt(i) == s.charAt(j)){
              i--;
              j++;
            }
            if(tail - head < --j - ++i){
              head = i ;
              tail = j ;
            }

}
}


Problem 241.Different Ways to Add Parentheses

Given a string of numbers and operators, return all possible results from computing all the different possible ways to group numbers and operators. The valid operators are +, - and *.


Example 1
Input: "2-1-1".


((2-1)-1) = 0
(2-(1-1)) = 2


Output: [0, 2]


Example 2
Input: "2*3-4*5"


(2*(3-(4*5))) = -34
((2*3)-(4*5)) = -14
((2*(3-4))*5) = -10
(2*((3-4)*5)) = -10
(((2*3)-4)*5) = 10

Output: [-34, -14, -10, -10, 10]


解题思路:

这里说两种解题思路,一种是自己的,另一种是在评论上看到的。

首先是自己的并不能通过的方法,因为重复计算了相同的算式,所以输出的结果冗余,但是我觉得思路上应该没有太大的问题所以还是稍微写一下,希望大家引以为戒:

1. 中心思想就是利用递归,不断地把相邻的两个数字合并起来,直到最后只剩一个数,也就是最终的一个结果,存放起来,然后循环往复:例如 "1+2+3-1",首先合并第一个和第二个数,合并之后变为"3+3-1",再合并为"6-1",最后得到结果5。然后考虑合并第二和第三个数...以此类推。

2.因为输入的是字符串,所以创建两个列表分别来存放读取出来的数字和符号。

代码如下:

public class Solution {
  private List<Integer> ans = new ArrayList<>();
    public List<Integer> diffWaysToCompute(String input) {

      int length = input.length();
      List<Integer> numList = getNums(input);
      List<Character> optList = getOpts(input);
      if(optList.size() == 0){
        return numList;
      }
      else{
        mergeNums(numList,optList);
        return ans;
      }
    }

    private List<Integer> getNums(String s){
        List<Integer> numList = new ArrayList<>();
        for(int i = 0;i< s.length();i++){
        int temp = i;
        while(temp < s.length() && s.charAt(temp) >= 48 && s.charAt(temp) <= 57){
          temp++;
        }
        int tail = temp > i ? temp : i;
        if(tail > i){
          try {
          int newNum = Integer.parseInt(s.substring(i,tail));
          numList.add(newNum);
          i = temp - 1;
      } catch (NumberFormatException e) {
          e.printStackTrace();
        }       
        }

        }
        return numList;

    }

     private List<Character> getOpts(String s){
        List<Character> optList = new ArrayList<>();
        for(int i = 0;i< s.length();i++){
          if(s.charAt(i) == '+' || s.charAt(i) == '-' || s.charAt(i) == '*'){
            optList.add(s.charAt(i));
          }           

        }
        return optList;

    }




    private void mergeNums(List<Integer> numlist, List<Character> optList){

      if(numlist.size() >= 2){
        for(int i = 0;i + 1 < numlist.size();i++){
          List<Integer> newNumList = new ArrayList<>();
          List<Character> newOptList = new ArrayList<>();
          newNumList.addAll(numlist); 
          newOptList.addAll(optList);
        int num1 = numlist.get(i);
        int num2 = numlist.get(i+1);
        int mer = 0;
        switch(optList.get(i)){
          case '+':
            mer = num1 + num2;
            break;
          case '-':
            mer = num1 - num2;
            break;
          case '*':
            mer = num1 * num2;
            break;
          default:
            break;
        }
              
          newNumList.set(i,mer);
          newNumList.remove(i+1);         
          newOptList.remove(i);
          mergeNums(newNumList,newOptList);
        }
      }
      if(numlist.size() == 1){
        ans.add(numlist.get(0));
      }
    }


}

这个思路看起来是没有问题,的确把所有可能的等式全部考虑到了,但是考虑了许多重复的情况,测试用例中的:

"2*3-4*5"

它的所有可能等式情况为:

(2*(3-(4*5))) = -34
((2*3)-(4*5)) = -14
((2*(3-4))*5) = -10
(2*((3-4)*5)) = -10
(((2*3)-4)*5) = 10

输出应该为:[-34, -14, -10, -10, 10]


但是用上面的代码运行出来的结果为:


可以发现结果中多了一个-14,这是为什么呢?因为上面的算法是主要考虑两个数字合并,当算式中,2和3合并的时候,已经考虑过了((2*3)-(4*5)) = -14这个情况,但是到了4和5进行合并时,这个情况又再一次被考虑到,虽然重复了但是还是被记录到了结果中,所以不能通过测试,由于我暂时还没有找到修改的办法,所以这里介绍另外一种更加简洁到位的算法。


1. 也是采用分而治之的递归方法,核心思想不是考虑两个数字的合并,而是从操作符出发,不断地把字符串根据操作符进行分割,直到分到不再有操作符,只剩数字之后再进行操作。

2.这种方法不需要单独的把数字和操作符都提取出来,因为在递归的最后一步,操作符应全部被提取出去了。

3. 用到了HashMap来记录字符串和对应计算结果,利用了键值的唯一性防止了重复计算,提高了代码效率。

代码如下:

public class Solution {
    
    Map<String, List<Integer>> map = new HashMap<>();
    
    public List<Integer> diffWaysToCompute(String input) {
        List<Integer> res = new ArrayList<>();
        for (int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);
            if (c == '+' || c == '-' || c == '*') {
                String p1 = input.substring(0, i);
                String p2 = input.substring(i + 1);
                List<Integer> l1 = map.getOrDefault(p1, diffWaysToCompute(p1));
                List<Integer> l2 = map.getOrDefault(p2, diffWaysToCompute(p2));
                for (Integer i1 : l1) {
                    for (Integer i2 : l2) {
                        int r = 0;
                        switch (c) {
                            case '+':
                                r = i1 + i2;
                                break;
                            case '-':
                                r = i1 - i2;
                                break;
                            case '*':
                                r = i1 * i2;
                                break;
                        }
                        res.add(r);
                    }
                }
            }
        }
        if (res.size() == 0) {
            res.add(Integer.valueOf(input));
        }
        map.put(input, res);
        return res;
    }
}

看着自己快100行还不能通过的代码以及别人一小段就可以AC的代码后,内心是十分抗拒的,感觉还有很长的路要走,在考虑算法的时候,还是应该要更加谨慎,不能简单粗暴的直接全部过一遍,这样既耗费资源,效率也很低。






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值