【字符串篇】力扣刷题2

test3. 无重复字符的最长子串

题目如下:
在这里插入图片描述
示例1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3

示例2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1

示例3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

在这里插入图片描述
解题思路
这一题的解法说白了就是双指针(官网上有一个好听的名字“滑动窗口”)。
我们使用两个指针i,j相当于窗口的左右边界,i代表着左边界,也就是初始位置,然后判断j指针对应的值与i对应的是否一样。

  • 如果不一样,我们向右移动j指针,不断扩大窗口范围;
  • 如果一样,我们将已经遍历过的内容长度存入数组,且跳出此轮循环,i指针向右移动。

Java代码

public static int lengthOfLongestSubstring(String s) {
        char[] ch = s.toCharArray();
        int[] nums = new int[ch.length];
        for (int i=0;i<ch.length-1;i++) {
            List<Character> list = new ArrayList<>();
            list.add(ch[i]);
            int j = i+1;
            while (ch[i]!=ch[j]) {
                if (!list.contains(ch[j])) {
                    list.add(ch[j]);
                    if (j< nums.length-1) {
                        j++;
                    }
                } else {
                    break;
                }
            }
            nums[i] = list.size();
        }
        Arrays.sort(nums);
        if (nums.length-1<0) {
            return 0;
        }
        if (nums.length-1==0) {
            return 1;
        }
        return nums[nums.length-1];
    }

JavaScript代码

/**
 * @param {string} s
 * @return {number}
 */
    var lengthOfLongestSubstring = function (s) {
      let str = s.split("");
      let nums = new Array(str.length);
      for (let i = 0; i < str.length - 1; i++) {
        let strs = [];
        strs.push(str[i]);
        let j = i + 1;
        while (str[i] != str[j]) {
          if (!strs.includes(str[j])) {
            strs.push(str[j]);
            if (j < str.length - 1) {
              j++;
            }
          } else {
            break;
          }
        }
        nums[i] = strs.length;
      }
      nums.sort((a, b) => a - b);
      if (nums.length - 1 < 0) {
        return 0;
      }
      if (nums.length - 1 == 0) {
        return 1;
      }
      //注意:JS这里是nums.length - 2,因为前面创建的nums数组我们没用完,没赋值的都是undefined
      return nums[nums.length - 2];
    };

test5. 最长回文子串

题目如下:
在这里插入图片描述
示例1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例2:

输入:s = "cbbd"
输出:"bb"

在这里插入图片描述
解题思路
尽管我每做一道题都在默念——千万别超时!千万别超时!!千万别超时!!!
但事实就是——我果然还是太年轻了,一看题就有思路,一输出就超时,这种感受谁懂啊喂~
以我目前的水平,只能这么暴力求解。

  • 首先,我们先来写个双重for循环“来挑衅一下时间复杂度”;
  • 然后在内层for循环里“动手”,截取字符串加if判断,来判断是否是回文子串(此处使用的是双指针来判断是否是回文子串);
  • 如果是回文子串,我们用max值来判断该回文子串的长度是否为最长,且将这个子串加入数组中(按照其长度作为下标),最后根据下标输出最长回文子串。

Java代码

//错误代码——超出时间限制
//    public static String longestPalindrome(String s) {
//        if (s.length()<2) {
//            return s;
//        }
//        String[] ch = new String[10000];
//        int max = 0;
//        for (int i=0;i< s.length();i++) {
//            for (int j=s.length();j>i;j--) {
//                StringBuilder sb1 = new StringBuilder(s.substring(i, j));
//                StringBuilder sb2 = new StringBuilder(s.substring(i, j));
//                sb1.reverse();
//                if (sb1.toString().equals(sb2.toString())) {
//                    max = max>sb1.length()?max:sb1.length();
//                    ch[sb1.length()] = sb2.toString();
//                }
//            }
//        }
//        return ch[max];
//    }
//正确代码——双指针解法
class Solution {
    public static String longestPalindrome(String s) {
        if (s.length()<2) {
            return s;
        }
        String[] ch = new String[10000];
        int max = 0;
        for (int i=0;i< s.length();i++) {
            for (int j=i;j<s.length();j++) {
            //一定要记得加j+1-i>max判断(条件限制——让后面进入panduan里的字符长度大于之前的),可以降低很多时间复杂度,并且一定要写在前面!!!
                if(j+1-i>max&&panduan(s.substring(i, j+1))) {
                    max=Math.max(max,j+1-i);
                    ch[j+1-i] = s.substring(i, j+1);
                }
            }
        }
        return ch[max];
    }
    //双指针——
    private static boolean panduan(String s){
        int l=0;
        int r =s.length()-1;
        while(l<r){
            if(s.charAt(l)!=s.charAt(r)){
                return false;
            }
            l++;
            r--;
        }
        return true;
    }
}
//正确代码——朋友的解法
    public static String longestPalindrome(String s) {
        int l = 0;
        String result = "";
        Map<Character, List<Integer>> map = new HashMap<>();
        //Map第一个方字母,第二个放这个字母索引的集合
        for (int i = 0; i < s.length(); i++) {
            List<Integer> orDefault = map.getOrDefault(s.charAt(i), new ArrayList<>());
            orDefault.add(i);
            map.put(s.charAt(i), orDefault);

            List<Integer> intArr = map.get(s.charAt(i));
            for (Integer index : intArr) {
                String str = s.substring(index, i + 1);
                int tempL = str.length();
                if (tempL > l && check(str)) {
                    l = tempL;
                    result = str;
                }
            }
        }
        return result;
    }

JavaScript代码

/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function (s) {
      let max = 0;
      let strs = [];
      for (let i = 0; i < s.length; i++) {
        for (let j = i; j < s.length; j++) {
          if (j + 1 - i > max&& huiwen(s.substring(i, j + 1)) ) {
            max = max > j + 1 - i ? max : j + 1 - i;
            strs[j + 1 - i] = s.substring(i, j + 1);
          }
        }
      }
      return strs[max]
      // console.log(strs[max]);
      function huiwen(str) {
        let l = 0;
        let r = str.length - 1
        stra = str.split('');
        while (l < r) {
          if (stra[l] != stra[r]) {
            return false;
          }
          l++;
          r--;
        }
        return true;
      }
    };
    longestPalindrome();

test13. 罗马数字转整数

题目如下:
在这里插入图片描述
示例1:

输入: s = "III"
输出: 3

示例2:

输入: s = "IV"
输出: 4

示例3:

输入: s = "IX"
输出: 9

示例4:

输入: s = "LVIII"
输出: 58
解释: L = 50, V= 5, III = 3.

示例5:

输入: s = "MCMXCIV"
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.

在这里插入图片描述
解题思路
这个题看起来很长很“恶心”,但是做起来很“简单”,只要懂得如何去存罗马数字对应的字符基本上就解决了一大部分。后半部分就根据题目所示的“步骤”去实现就ok啦!

Java代码

public static int romanToInt(String s) {
        Map<Character,Integer> ch = new HashMap<Character,Integer>() {
            {
                put('I',1);
                put('V',5);
                put('X',10);
                put('L',50);
                put('C',100);
                put('D',500);
                put('M',1000);
            }
        };
        int n = 0;
        for (int i=0;i<s.length();i++) {
            int a = ch.get(s.charAt(i));
            if (i<s.length()-1&&a<ch.get(s.charAt(i+1))) {
                n-=a;
            } else {
                n+=a;
            }
        }
        return n;
    }

JavaScript代码

/**
 * @param {string} s
 * @return {number}
 */
var romanToInt = function (s) {
      const str = s.split('');
      const m1 = new Map([
        ['I', '1'],
        ['V', '5'],
        ['X', '10'],
        ['L', '50'],
        ['C', '100'],
        ['D', '500'],
        ['M', '1000'],
      ])
      let n = 0;
      for (let i = 0; i < str.length; i++) {
        let a = m1.get(str[i]) * 1;
        if (i < str.length - 1 && a < m1.get(str[i + 1])) {
          n -= a;
        } else {
          n += a;
        }
      }
      return n;
    };

test14. 最长公共前缀

题目如下:
在这里插入图片描述
示例1:

输入:strs = ["flower","flow","flight"]
输出:"fl"

示例2:

输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。

在这里插入图片描述
解题思路
这个题其实有点绕,因为它的两个for循环,有点不符合正常的循环思路。
外循环(i)是用来遍历第一个字符串的所有字符;
内循环(j)是用来遍历所有的字符串;
当我们进入到内循环的时候,对所有的字符串的第i位进行判断,如果都相等,我们进入外循环i的下一步,否则,就返回结果。
Java代码

public static String longestCommonPrefix(String[] str) {
        String res = "";
        if (str.length==0) return "";
        for (int i=0;i<str[0].length();i++) {
            char c = str[0].charAt(i);
            for (String st : str) {
                if (i>st.length()-1) return res;
                if (st.charAt(i) != c) return res;
            }
            res += str[0].charAt(i);
        }
        return res;
    }

JavaScript代码

/**
 * @param {string[]} strs
 * @return {string}
 */
var longestCommonPrefix = function (strs) {
      let res = ""
      if (strs.length == 0) return "";
      for (let i = 0; i < strs[0].length; i++) {
        let s1 = strs[0].split('');
        for (let j = 1; j < strs.length; j++) {
          let s2 = strs[j].split('');
          if (i > strs[j].length - 1) return res;
          if (s2[i] != s1[i]) return res;
        }
        res += s1[i];
      }
      // console.log(res);
      return res;

    };

test20. 有效的括号

在这里插入图片描述
示例1:

输入:s = "()"
输出:true

示例2:

输入:s = "()[]{}"
输出:true

示例3:

输入:s = "(]"
输出:false

在这里插入图片描述
解题思路
这道题需要用到「栈」来解决,我们可以来了解一下java中stack的使用方法——堆栈是一种"后进先出"的数据结构,只能在一端进行插入(称为"压栈")或删除(称为"出栈")数据的操作。

  • 存:根据题目的要求,左右括号一对一闭合且按照正确的顺序,意思就是先遇到的左括号要后闭合,后遇到的左括号要先闭合,即{[()]}这种闭合方式,因此我们需要将后遇到的左括号放在栈顶(此处我存放的是左括号对应的右括号)。
  • 删:当遍历到一个右括号时,我们取出之前放在栈顶的括号来判断是否一样,如果不一样,我们就返回false。

Java代码

public static boolean isValid(String s) {
        //Stack 栈是一个 "先进后出"的原理,本质是一个List,其具备 List 所有方法
        Stack<Character> stack = new Stack<Character>();
        for (char c: s.toCharArray()){
            if (c == '(')stack.push(')');
            else if (c == '[')stack.push(']');
            else if (c == '{')stack.push('}');
            else if (stack.isEmpty()||c!=stack.pop()) return false;
        }
        //判断Stack是否为空
        return stack.isEmpty();
    }

JavaScript代码

/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function (s) {
      if (s.length == 1) {
        return false;
      }
      const str = [];
      for (st of s.split('')) {
        if (st === '(') str.push(')');
        else if (st == '[') str.push(']');
        else if (st == '{') str.push('}');
        else if (str.length == 0 || st != str.pop()) return false;
      }
      if (str.length == 0) {
        return true;
      } else {
        return false;
      }
    };

test67. 二进制求和

在这里插入图片描述
示例1:

输入:a = "11", b = "1"
输出:"100"

示例2:

输入:a = "1010", b = "1011"
输出:"10101"

在这里插入图片描述
解题思路
啥也不说了,我是真的很讨厌进制的题型(好吧,我承认我讨厌的题型多了去了),每次都是在不断地错误输出中找到“路”。要求是以二进制字符串的形式返回它们的和,就在我暗自窃喜直接Integer.parseInt(a,2)+Integer.parseInt(b,2)输出时,结果就啪啪打脸,它当然不会让你那么愉快地通过了,明确的说报错原因是当字符过长时类型转换出错了。那就没办法,我们另辟蹊径吧!
在旁边一位大佬的指点下,我幡然醒悟,它不是让求和嘛,那我们直接让字符a和b以数字类型先相加,然后逢2进1,就能得到最终结果;想法很简单,但是具体操作起来其实要考虑的地方挺多的,比如当相加之后为222时,还要考虑2进位得3的情况;而且其中很多地方都是靠替换解决的。

Java代码

import java.math.BigInteger;
class Solution {
    public static String addBinary(String a, String b) {
    StringBuilder ans = new StringBuilder();
        BigInteger c = new BigInteger(b).add(new BigInteger(a));
        String str = c.toString();

        for (int i = 0;i<str.length();i++) {
            ans.append(str.charAt(i));
        }
        int n=0;
        for (int i=str.length()-1;i>=0;i--) {

            if (ans.charAt(i)=='2' && i!=0) {
                ans.replace(str.length()-1-n,str.length()-n,"0");
                if (ans.charAt(i-1)=='1') {
                    ans.replace(str.length()-2-n,str.length()-1-n,"2");
                } else if (ans.charAt(i-1)=='0'){
                    ans.replace(str.length()-2-n,str.length()-1-n,"1");
                } else if (ans.charAt(i-1)=='2') {
                    ans.replace(str.length()-2-n,str.length()-1-n,"3");
                }
            }
            if (ans.charAt(i)=='3' && i!=0) {
                ans.replace(str.length()-1-n,str.length()-n,"1");
                if (ans.charAt(i-1)=='1') {
                    ans.replace(str.length()-2-n,str.length()-1-n,"2");
                } else if (ans.charAt(i-1)=='0'){
                    ans.replace(str.length()-2-n,str.length()-1-n,"1");
                } else if (ans.charAt(i-1)=='2') {
                    ans.replace(str.length()-2-n,str.length()-1-n,"3");
                }
            }
            if (i==0&& ans.charAt(i)=='2') {
                ans.replace(0,1,"0");
                ans.insert(0,"1");
            }
            if (i==0&& ans.charAt(i)=='3') {
                ans.replace(0,1,"1");
                ans.insert(0,"1");
            }
            n++;
        }
        return ans.toString();

    }
}

上面的代码虽然最终都运行通过了,但仔细看的话,还是不够“优雅”。如果你有更好的解法,请和我分享叭~
如有错误,请指正!
在这里插入图片描述在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值