力扣字符串专题


简单题我重拳出击,复杂题我唯唯诺诺!!!


力扣344题:反转字符串

思路 :

思路很简单,就是定义两个指针,前后依次交换数组中的元素,之后头指针++,尾指针- -,直到不满足循环条件退出循环

代码如下:

class Solution {
    public void reverseString(char[] s) {
        int i = 0, j = s.length - 1;
        while(i < j) {
            char temp = s[i];
            s[i] = s[j];
            s[j] = temp;
            i++;
            j--;
        }
    }
}

做完上边这个题之后,我们再看下边这个!!!

力扣541题:反转字符串 II

思路如下:

首先需要把字符串变成一个字符数组,之后对字符数组进行操作。每2k个元素操作一次,假如要操作的元素不足k个,我们直接对这些所有的元素进行操作,遍历完之后,返回一个新的字符串。

代码如下:

二刷自己手写版:

class Solution {
    public String reverseStr(String s, int k) {
        char[] arr = s.toCharArray();
        for(int i = 0; i < arr.length; i += 2*k) {
            if(i + k < arr.length) {
                reverseSubStr(arr, i, i+k-1);
            } else {
                reverseSubStr(arr, i, arr.length-1);
            }
        }
        // StringBuffer sb = new StringBuffer();
        // for(char c : arr) {
        //     sb.append(c);
        // }
        // return sb.toString();

        return new String(arr);
    }
    public void reverseSubStr(char[] arr, int start, int end) {
        while(start < end) {
            char temp = arr[start];
            arr[start] = arr[end];
            arr[end] = temp;
            start++;
            end--;
        }
    }
}

一刷参考别人版:

class Solution {
    public String reverseStr(String s, int k) {
        char[] arr = s.toCharArray();
        for(int i = 0; i < arr.length; i += 2 * k) {
            int start = i;
            //1. 可以用Math函数比大小,选用
            // int end = Math.min(arr.length - 1, start + k - 1);
            //2. 也可以用三元运算来确定末尾指针的位置
            int end = arr.length-1 < start+k-1 ? arr.length-1 : start+k-1;
            while(start < end) {
                char temp = arr[start];
                arr[start] = arr[end];
                arr[end] = temp;
                start++;
                end--;
            }
        }
        return new String(arr);
    }
}

假期第一天,就做了这两道题,哈哈哈,属实是划水摸鱼了,以后慢慢提上效率来了得,奥里给给给!!!

今天的第一道题就是替换空格呀,难倒是不是很难,就是我不会呀,哈哈哈。问题不大,看看题解,哦!!!原来是这么做呀,码起来======》

剑指Offer第5题:替换空格

思路:

首先得拿到所给字符串的长度吧,拿到长度之后需要创建一个3倍长度的字符数组(为什么呢?由题可知,人家不是要求我们把空格替换成%20嘛,一变三,尽管不一定全用的到,最起码有必要啊),之后遍历字符串的每一个字符,判断是否为空,若是,依次替换,size加3;若不是,把该字符拿过来(拿来吧你!!!)size加1。注意:这里边的size指的是最后新字符串的长度,最后返回一个新字符串(拷贝数组arr从0到size)。

代码如下:

自己二刷代码:

class Solution {
    public String replaceSpace(String s) {
        StringBuffer sb = new StringBuffer();
        char[] arr = s.toCharArray();
        for(char c : arr) {
            if(c == ' ') {
                sb.append("%20");
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }
}

一刷参考别人代码:

class Solution {
    public String replaceSpace(String s) {
        int length = s.length();
        char[] arr = new char[length * 3];
        int size = 0;
        for(int i = 0; i < length; i++) {
            char c = s.charAt(i);
            if(c == ' ') {
                arr[size++] = '%';
                arr[size++] = '2';
                arr[size++] = '0';
            } else {
                arr[size++] = c;
            }
        }
        return new String(arr, 0, size);
    }
}

看完别人的题解之后,我感觉我又行了,哈哈哈(菜鸡自我感觉良好,呜呜呜)

紧接着又做了第二个题,不做还好,一做又掉了几根头发,可谓是难呀!哈哈哈!!!

总结:二刷自己写的在空间上节约点,时间上二者差不多。

	今天从醒来打开电脑就开始帮别人处理数据了,你敢信?每个人的数据都得有一个专属的配套处理方式,哎呀,尽管是东拼西凑出来的代码,那也得会拼凑啊,这就好比是一个人,每个人都有自己适合的穿衣风格,专属发型,呵呵呵,闲话不说,直接进入正题。
	今日第一题就碰壁了,理解起来不复杂,需要对一些方法有所了解。

力扣151题:颠倒字符串中的单词

解题思路:

第一步===》去除所有空格(包括字符串前、后以及中间)
第二步===》反转整个字符串(前后对应对调)
第三步===》反转每个单词(从左往右遍历,以空格为单词区分,进行翻转)

代码如下:

class Solution {
    public String reverseWords(String s) {
        StringBuilder sb = removeSpace(s);
        reverse(sb, 0, sb.length()-1);
        reverseEachWord(sb);
        return sb.toString();

        //反转每个单词
        public void reverseEachWord(StringBuilder sb) {
            int begin = 0, end = 0;
            while(begin < sb.length()) {
                while(end < sb.length() && sb.charAt(end) != ' ') {
                    end++;
                }
                reverse(sb, begin, end - 1);
                begin = end + 1;
                end++;
            }
        }
        //反转字符串
        public void reverse(StringBuilder sb, int left, int right) {
            while(left < right) {
                char temp = sb.charAt(left);
                sb.setCharAt(left, sb.charAt(right));
                sb.setCharAt(right, temp);
                left++;
                right--;
            }
        }
        //清空空格
        public StringBuilder removeSpace(String s) {
            int left = 0, right = s.length()-1;
            //清除字符串左边的所有空格
            while(left <= right && s.charAt(left) == ' ') {
                left++;
            }
            //清除字符串右边的所有空格
            while(left <= right && s.charAt(right) == ' ') {
                right++;
            }
            //清除中间部分的空格
            StringBuilder sb = new StringBuilder();
            while(left <= right) {
                char c = s.charAt(left);
                if(c != ' ' || sb.charAt(sb.length() - 1) != ' ') {
                    sb.append(c);
                }
                left++;
            }
            return sb;
        }

    }
}

public void setCharAt(int pos, char c);
参数:

int pos – represents the position where we want to set the given character.

int pos –表示我们要设置给定字符的位置。

char c – represents the new character which we want to place.

char c –表示我们要放置的新字符。 

不得不说,只要有一个单词打错,你真的是找不到啊!我这个题就因为reverse(sb, 0, sb.length()-1);中的sb写成s,他错误还在reverse函数本身,哈哈哈,真是鸡肋呀!

剑指 Offer 58 - II. :左旋转字符串

解题思路:

我怎么感觉这个题是一个智力题,哈哈!
分为三步===>第一步:翻转0~n-1之间的字符串
第二步:翻转n~末尾的字符串
第三步:全部翻转

代码如下:

class Solution {
    public String reverseLeftWords(String s, int n) {
        StringBuilder sb = new StringBuilder(s);
        reverse(sb, 0, n-1);
        reverse(sb, n, s.length()-1);
        reverse(sb, 0, s.length()-1);
        return sb.toString();
    }
    public StringBuilder reverse(StringBuilder sb, int start, int end) {
        while(start < end) {
            char temp = sb.charAt(start);
            sb.setCharAt(start, sb.charAt(end));
            sb.setCharAt(end, temp);
            start++;
            end--;
        }
        return sb;
    }
}

力扣165题:比较版本号

解题思路:

首先,以 点 为分隔符,取出来转成数字,比较大小,最后返回相应的数字即可。

代码如下:

class Solution {
    public int compareVersion(String version1, String version2) {
        int i = 0, j = 0;
        //version1,version2 只要有一个没遍历完就接着遍历
        while(i < version1.length() || j < version2.length()) {
            int x = 0, y = 0;
            //对于version1来说,以'.'为分隔,依次取出字符串
            while(i < version1.length() && version1.charAt(i) != '.') {
                //字符串 转 数字 比大小
                x = x*10 + version1.charAt(i) - '0';  
                i++;
            }
            while(j < version2.length() && version2.charAt(j) != '.') {
                y = y*10 + version2.charAt(j) - '0';
                j++;
            }
            //比完之后返回相应的数
            if(x > y) {
                return 1;
            } else if(x < y) {
                return -1;
            }
            i++;
            j++;
        }
        return 0;
    }
}

今天除夕夜,力扣人respect!!!
在这里祝愿所有好厚米新年快乐,万事如意,都能如愿以偿。

力扣929题:独特的电子邮件地址

解题思路:

首先我们要将email字符串进行分割,以@为标志,前边为本地名local,后边为domain域名,域名不用判断,".“和”+“在域名中没有那样的规则;我们着重去处理本地名,先把”+“之后的省略掉,之后将所有的”."都替换成空,此处可以用String类的replace方法和replaceAll方法,参见文献1.

代码如下:

class Solution {
    public int numUniqueEmails(String[] emails) {
        //因为只放一个值,用Set和List足矣,但是我们这里要求不能重复,所有只能选用Set
        Set<String> hashset = new HashSet<>();
        //增强for
        for(String email : emails) {
            //找出@索引并且取出前后作为local和domain
            int index = email.indexOf('@');
            String local = email.substring(0, index);
            String domain = email.substring(index);
            //判断local中是否包含+,有的话只要前边的
            if(local.contains("+")) {
                local = local.substring(0, local.indexOf('+'));
            }
            //替换 .
            // local = local.replaceAll("\\.", "");
            local = local.replace(".", "");
            //往hashset添加
            hashset.add(local + domain);
        }
        return hashset.size();
    }
}

力扣5题:最长回文子串

解题思路:

从左至右依次将字符作为回文字符串的中间字符,如果s是单数,则从中间的一个开始向左向右开始遍历;如果是双数,则从中间的两个开始分别从左从右开始遍历。

代码如下:

class Solution {
    public String longestPalindrome(String s) {
        String res = "";
        for(int i = 0; i < s.length(); i++) {
            int j, k;
            //s长度为奇数
            for(j = i, k = i; j >= 0 && k < s.length() && s.charAt(j) == s.charAt(k); j--, k++) {
                if(res.length() < k-j+1) {
                    res = s.substring(j, k+1);
                }
            }
            //s长度为偶数
            for(j = i, k = i+1; j >= 0 && k < s.length() && s.charAt(j) == s.charAt(k); j--, k++) {
                if(res.length() < k-j+1) {
                    res = s.substring(j, k+1);
                }
            }
        }
        return res;
    }
}

参考文献:

1.replace java_Java中String类下的replace和replaceAll方法的区别

力扣38题:外观数列

思路:先定义一个基本字符串,从这个字符串开始,依次递推,逐层遍历,在数重复字符的时候,通过双指针可以数出来重复的个数,再进行转换字符串和字符串拼接的操作。
代码如下:

class Solution {
    public String countAndSay(int n) {
        String s = "1";
        for(int i = 0; i < n - 1; i++) {
        // for(int i = 2; i <= n; ++i) {
            //这里不能用String来解题了,Java中的String是定长的,定义一个StringBuilder对象
            StringBuilder sb = new StringBuilder();
            // String ns = null;
            for(int j = 0; j < s.length(); j++) {
                int k = j;
                while(k < s.length() && s.charAt(k) == s.charAt(j)) {
                    k++;
                }
                sb.append(Integer.toString(k - j)).append(s.charAt(j));
                // ns += toString(k - j) + s.charAt(j);
                //这里可不是j = k 呀,因为for循环里还有个j++操纵,操作完才是j = k
                j = k - 1;
            }
            s = sb.toString();
        }
        return s;
    }
}

这个体中注意的是不能用String来解题了,Java中的String是定长的,定义一个StringBuilder对象这点很重要!!!

力扣49题:字母异位词分组

同样是思想很简单,但是呢,考察的集合知识很麻烦,同样是看了别人的题解,发现自己有个API没见过,不过不要慌,查查文档就找到了,拿下!!!

解题思路:

字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。先得知道什么是字母异位词,找到突破口,那我们就给每个字符串排下序,如果排序之后的字符串相同,那说明属于一类呗!把每一类作为map的键key,之后值用一个List存放字符串,最后返回List内容就完事了呗!

代码如下:

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        Map<String, List<String>> map = new HashMap<>();
        for(String str : strs) {
            char[] arr = str.toCharArray();
            Arrays.sort(arr);
            String key = new String(arr);
            List<String> list = map.getOrDefault(key, new ArrayList<String>());
            list.add(str);
            map.put(key, list);
        }
        return new ArrayList<List<String>>(map.values());
    }
}

不会还得多看看别人的题解啊,自己埋头苦干犹如坐进观天,别说浪费时间了,心态都给你搞崩喽!

离开力扣两三天,手就痒痒啊!完了,彻底中毒了,哈哈哈!!!

力扣第3题:无重复字符的最长子串

解题思路:

首先肯定想到的是暴力解法,双指针,里外循环一起走,但是这个时间复杂度为O(n2),为了减少时间复杂度,我们让内循环(左指针)不回头的遍历,拿到一个ans的字符子串长度,丢弃左指针的字符,右指针判断下一个位置的字符是否与现在的字符子串内的字符重复,不重复就加进来,重复就不加,左指针继续向右走。直到越界。

代码如下:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        //储存不重复的字符
        Set<Character> hashset = new HashSet<>();
        //将右指针至于左边界的左端
        int right = -1;
        int ans = 0;
        //遍历左指针,记录最长字符子串。扔掉最左边的一个字符,右指针往右走看看是否比上一组字符子串长,长就记录下来
        for(int left = 0; left < s.length(); left++) {
            if(left != 0) {
                hashset.remove(s.charAt(left - 1));
            }
            while(right+1 < s.length() && !hashset.contains(s.charAt(right + 1))) {
                hashset.add(s.charAt(right + 1));
                right++;
            }
            ans = Math.max(ans, right - left + 1);
        }
        return ans;
    }
}

完蛋,晚上遇到一个题,看了别人题解没想明白,哈哈哈,现在脑袋都大了,明天再看看吧,呜呜呜!!!

力扣28题:实现 strStr()

解题思路:

摊牌了,不装了,这道题我选择不理解,就是背,哈哈哈!一些理解在代码注释中

代码如下:

class Solution {
    //获取next数组的方法
    public void getNext(int[] next, String s) {
        //第一步:初始化
        int j = -1;
        next[0] = j;
        //遍历模式串s
        for(int i = 1; i < s.length(); i++) {
            //第二步:处理前后缀不相同的情况
            while(j >= 0 && s.charAt(i) != s.charAt(j+1)) {
                j = next[j];
            }
            //第三步:处理前后缀相同的情况
            if(s.charAt(i) == s.charAt(j+1)) {
                j++;
            }
            next[i] = j;
        }
    }
    public int strStr(String haystack, String needle) {
        //特判
        if(needle.length() == 0) {
            return 0;
        }
        //定义一个大小为needle字符串长的一个整数数组next
        int[] next = new int[needle.length()];
        //更新next数组
        getNext(next, needle);
        //定义模式串needle的起始位置,从-1开始,因为next数组就是从-1开始的
        int j = -1;
        //遍历文本串haystack,从0开始
        for(int i = 0; i < haystack.length(); i++) {
            //文本串和模式串不等时怎么处理?
            while(j >= 0 && haystack.charAt(i) != needle.charAt(j+1)) {
                j = next[j];
            }
            //文本串和模式串相等时怎么处理?
            if(haystack.charAt(i) == needle.charAt(j+1)) {
                j++;
            }
            //当j跑到了模式串的末尾,说明文本串里出现了模式串,因为题中要求返回出现的起始位置,所以返回i - needle.length() + 1
            if(j == needle.length() - 1) {
                return (i - needle.length() + 1);
            }
        }
        //如果跑完都没出现,说明就没有,返回-1
        return -1;
    }
}

同样遇到另一道题,思路大致相同,只是最后处理有一些不同,大同小异!

力扣459题:重复的子字符串

解题思路:

感觉把KMP算法如何更新next数组的步骤记住就可以做题了,同28题,我这里写了两种方式

代码如下:

class Solution {
    //方法一,借鉴28题
    public void getNext(int[] next, String s) {
        //初始化
        int j = -1;
        next[0] = j;
        for(int i = 1; i < s.length(); i++) {
            //第二步:处理前后缀不相同的情况
            while(j >= 0 && s.charAt(i) != s.charAt(j+1)) {
                j = next[j];
            }
            //第三步:处理前后缀相同的情况
            if(s.charAt(i) == s.charAt(j+1)) {
                j++;
            }
            next[i] = j;
        }
    }
    public boolean repeatedSubstringPattern(String s) {
        if(s.length() == 0) {
            return false;
        }
        int[] next = new int[s.length()];
        getNext(next, s);
        if(next[s.length()-1] != -1 && s.length() % (s.length() - (next[s.length()-1] + 1)) == 0) {
            return true;
        }
        return false;

        //方法二
        if(s.length() == 0) {
            return false;
        }
        int length = s.length();
        // 原串加个空格(哨兵),使下标从1开始,这样j从0开始,也不用初始化了
        s = " " + s;
        int[] next = new int[length + 1];
        // 构造 next 数组过程,j从0开始(空格),i从2开始
        for(int i = 2, j = 0; i < length + 1; i++) {
            while(j > 0 && s.charAt(i) != s.charAt(j + 1)) {
                j = next[j];
            }
            if(s.charAt(i) == s.charAt(j+1)) {
                j++;
            }
            next[i] = j;
        }
        if(next[length] > 0 && length % (length - next[length]) == 0) {
            return true;
        }
        return false;
    }
}

不得不说,这题真不是给我这种凡夫俗子做的,哈哈哈,都是大佬!!!
到今天为止,字符串就先告一段落了,明天开始“双指针” 的学习,奥力给!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值