代码随想录算法训练营第八天


​#️⃣ PC端可在链接处悬停查看题目来源

LeetCode/卡码网题目

  • 151. 反转字符串中的单词
  • 55. 右旋字符串(第八期模拟笔试)
  • 28. 找出字符串中第一个匹配项的下标
  • 459. 重复的子字符串
  • 2874. 有序三元组中的最大值 II(每日一题)
  • 总结
  • 往期打卡


151. 反转字符串中的单词

跳转: 151. 反转字符串中的单词

问题:

给你一个字符串 s ,请你反转字符串中 单词 的顺序。

单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。

返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。

**注意:**输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。

思路:

左右双指针全局翻转,然后对每个单词局部翻转(翻转两次等于自身,故可以实现调换)
(在C/C++中可以 O ( 1 ) O(1) O(1)原地替换)

复杂度:

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

代码:

class Solution {
    public String reverseWords(String s) {
        int n = s.length();
        char[] ch = s.toCharArray();
        reverseCharArray(ch,0,n-1);
        int i = 0;
        int k = 0;
        while (k < n) {
            if(ch[k]==' '){
                k++;
                continue;
            }
            if(i!=0) ch[i++] = ' ';
            int j = i;
            while (k < n && ch[k] != ' ')
                ch[j++] = ch[k++];
            reverseCharArray(ch,i,j-1);
            i = j;
        }
        return new String(ch,0,i);
    }
    private void reverseCharArray(char[] ch,int s,int e){
        while (s<e) {
            char t = ch[s];
            ch[s++] = ch[e];
            ch[e--] = t;
        }
    }
}

55. 右旋字符串(第八期模拟笔试)

跳转: 55. 右旋字符串(第八期模拟笔试)

问题:

字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k,请编写一个函数,将字符串中的后面 k 个字符移到字符串的前面,实现字符串的右旋转操作。

例如,对于输入字符串 “abcdefg” 和整数 2,函数应该将其转换为 “fgabcde”。

思路:

全部翻转 + 局部翻转 = 前后局部调换
(在C/C++中可以 O ( 1 ) O(1) O(1)原地替换)

复杂度:

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

代码:

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int r = sc.nextInt();
		char[] ch = sc.next().toCharArray();
        int n = ch.length-1;
        reverseCharArray(ch,0,n);
        reverseCharArray(ch,0,r-1);
        reverseCharArray(ch,r,n);
		System.out.println(ch);
	}
    private static void reverseCharArray(char[] ch,int s,int e){
        while (s<e) {
            char t = ch[s];
            ch[s++] = ch[e];
            ch[e--] = t;
        }
    }
}

28. 找出字符串中第一个匹配项的下标

跳转: 28. 找出字符串中第一个匹配项的下标

问题:

给你两个字符串 haystackneedle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1

思路:

KMP算法,记录子串的最长重复前缀下标,此处next数组value的含义是下一处不匹配从value处开始再比较(一直不匹配前缀会缩短至0)

复杂度:

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

代码:

class Solution {
    public int strStr(String haystack, String needle) {
        int[] next = kmp(needle);
        int j=0;
        int i=0;
        while(i<haystack.length()&&j<needle.length()){
            if(haystack.charAt(i)==needle.charAt(j)) j++;
            else if(j>0){
                j = next[j-1];
                continue;
            }
            i++;
        }
        if(j>=needle.length()){
            return i-j;
        }
        else return -1;
    }

    private int[] kmp(String s) {
        int[] next = new int[s.length()];
        int l = 0;
        int r = 1;
        while ( r < s.length() ) {
            if (s.charAt(r) == s.charAt(l)) {
                l++;
            } else if(l>0) {
                l = next[l-1];
                continue;
            }
            next[r++] = l;
        }
        return next;
    }
}

459. 重复的子字符串

跳转: 459. 重复的子字符串

问题:

给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。

思路:

是子串重复得到的话,长度与最后一个元素的next值查就是最小重复子串长L.
之后判断长度是否是倍数(有可能没重复完),判断是否是最小重复子串(至少下一个循环next会为L,要加一步合法性判断)

复杂度:

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

代码:

class Solution {
    public boolean repeatedSubstringPattern(String s) {
        int[] next = kmp(s);
        int r = next[s.length() - 1];
        if (r == 0)
            return false;
        int l = (s.length() - r);
        if(s.length()%l!=0) return false;
        int n = 2 * l - 1;
        if (n >= s.length())
            return false;
        if (next[n] == l)
            return true;
        return false;
    }

    private int[] kmp(String s) {
        int[] next = new int[s.length()];
        int l = 0;
        int r = 1;
        while (r < s.length()) {
            if (s.charAt(r) == s.charAt(l)) {
                l++;
            } else if (l > 0) {
                l = next[l - 1];
                continue;
            }
            next[r++] = l;
        }
        return next;
    }
}

2874. 有序三元组中的最大值 II(每日一题)

跳转: 2874. 有序三元组中的最大值 II

问题:

给你一个下标从 0 开始的整数数组 nums

请你从所有满足 i < j < k 的下标三元组 (i, j, k) 中,找出并返回下标三元组的最大值。如果所有满足条件的三元组的值都是负数,则返回 0

下标三元组 (i, j, k) 的值等于 (nums[i] - nums[j]) * nums[k]

思路:

贪心,维护好历史最值即可线性解决

复杂度:

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)

代码:

class Solution {
    public long maximumTripletValue(int[] nums) {
        long res = 0;
        int max = nums[0];
        int diffMax = nums[0]-nums[1];
        for(int i=2;i<nums.length;i++){
            res = Math.max((long)diffMax*nums[i],res);
            max = Math.max(max,nums[i-1]);
            diffMax = Math.max(diffMax,max-nums[i]);
        }
        return res;
    }
}

总结

练习了KMP和双指针翻转

往期打卡

代码随想录算法训练营第一天
代码随想录算法训练营第二天
代码随想录算法训练营第三天
代码随想录算法训练营第四天
代码随想录算法训练营周末一
代码随想录算法训练营第五天
代码随想录算法训练营第六天
代码随想录算法训练营第七天

你可能感兴趣的:(代码随想录打卡,算法)