leecode更新
This commit is contained in:
parent
c1f0422617
commit
04c495fbb9
|
|
@ -19,7 +19,7 @@ import java.util.stream.Stream;
|
||||||
* 注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
|
* 注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
|
||||||
* @Version: 1.0
|
* @Version: 1.0
|
||||||
*/
|
*/
|
||||||
public class ReverseWords {
|
public class T04_ReverseWords {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() {
|
public void test() {
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
package com.markilue.leecode.string;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.string
|
||||||
|
*@Author: dingjiawen
|
||||||
|
*@CreateTime: 2022-12-30 11:48
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣 剑指offer58题 左旋转字符串:
|
||||||
|
* 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。
|
||||||
|
* 比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T05_ReverseLeftWords {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
String s = "abcdefg";
|
||||||
|
int k = 2;
|
||||||
|
System.out.println(reverseLeftWords(s,k));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1(){
|
||||||
|
String s = "lrloseumgh";
|
||||||
|
int k = 6;
|
||||||
|
System.out.println(reverseLeftWords(s,k));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:和T04很像,比T04简单
|
||||||
|
* 速度击败52.3%,内存击败28.97%
|
||||||
|
* @param s
|
||||||
|
* @param n
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String reverseLeftWords(String s, int n) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
char[] chars = s.toCharArray();
|
||||||
|
int right=n;
|
||||||
|
while (n<chars.length){
|
||||||
|
builder.append(chars[n++]);
|
||||||
|
}
|
||||||
|
int left=0;
|
||||||
|
while (left<right){
|
||||||
|
builder.append(chars[left++]);
|
||||||
|
}
|
||||||
|
return new String(builder);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代码随想录思路:使用常数空间法,先反转前面在反转后面,在反转整个,就得到了左旋后的
|
||||||
|
* 速度击败18.89%,内存击败27.72% 7ms
|
||||||
|
* @param s
|
||||||
|
* @param n
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String reverseLeftWords1(String s, int n) {
|
||||||
|
int len=s.length();
|
||||||
|
StringBuilder sb=new StringBuilder(s);
|
||||||
|
reverseString(sb,0,n-1);
|
||||||
|
reverseString(sb,n,len-1);
|
||||||
|
return sb.reverse().toString();
|
||||||
|
}
|
||||||
|
public void reverseString(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--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方最快:直接subString解决问题
|
||||||
|
* 速度击败100%,内存击败41.79% 0ms
|
||||||
|
* @param s
|
||||||
|
* @param n
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String reverseLeftWords2(String s, int n) {
|
||||||
|
if (s == null)
|
||||||
|
return null;
|
||||||
|
return s.substring(n) + s.substring(0, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,7 +18,7 @@ import java.util.Arrays;
|
||||||
* 对于本题而言,当needle是空字符串时我们应当返回 0 。这与 C 语言的strstr()以及 Java 的indexOf()定义相符。
|
* 对于本题而言,当needle是空字符串时我们应当返回 0 。这与 C 语言的strstr()以及 Java 的indexOf()定义相符。
|
||||||
* @Version: 1.0
|
* @Version: 1.0
|
||||||
*/
|
*/
|
||||||
public class StrStr {
|
public class T06_StrStr {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() {
|
public void test() {
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
package com.markilue.leecode.string.second;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.string.second
|
||||||
|
*@Author: dingjiawen
|
||||||
|
*@CreateTime: 2022-12-30 10:05
|
||||||
|
*@Description:
|
||||||
|
* TODO 二刷力扣151题 反转字符串中的单词:
|
||||||
|
* 给你一个字符串 s ,请你反转字符串中 单词 的顺序。
|
||||||
|
* 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
|
||||||
|
* 返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
|
||||||
|
* 注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T04_ReverseWords {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
String s = " hello world ";
|
||||||
|
System.out.println(reverseWords(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:核心删除前后空格,中间空格只保留一个
|
||||||
|
* 先删除前后,在反转全部顺便去除中间多余空格,最后反转单词
|
||||||
|
* 速度击败96.92%,内存击败29.87% 2ms
|
||||||
|
* @param s
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String reverseWords(String s) {
|
||||||
|
char[] chars = s.toCharArray();
|
||||||
|
//先找到前后最先不是空格的位置
|
||||||
|
int start = 0;
|
||||||
|
int end = chars.length - 1;
|
||||||
|
while (chars[start] == ' ') {
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
while (chars[end] == ' ') {
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
//去除内部空格并整体反向
|
||||||
|
char[] newChar = new char[chars.length];
|
||||||
|
int k = 0;
|
||||||
|
while (end >= start) {
|
||||||
|
if (chars[end] != ' ' || chars[end + 1] != ' ') {
|
||||||
|
newChar[k++] = chars[end--];
|
||||||
|
} else {
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char[] result = Arrays.copyOf(newChar, k);
|
||||||
|
//反转内部单词
|
||||||
|
int left = 0;
|
||||||
|
int right = 0;
|
||||||
|
while (right < result.length) {
|
||||||
|
if (right == result.length - 1) {
|
||||||
|
reverse(result, left, right);
|
||||||
|
}
|
||||||
|
if (result[right] == ' ') {
|
||||||
|
reverse(result, left, right - 1);
|
||||||
|
left = right + 1;
|
||||||
|
}
|
||||||
|
right++;
|
||||||
|
}
|
||||||
|
return new String(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void reverse(char[] chars, int start, int end) {
|
||||||
|
char temp;
|
||||||
|
while (start < end) {
|
||||||
|
temp = chars[start];
|
||||||
|
chars[start] = chars[end];
|
||||||
|
chars[end] = temp;
|
||||||
|
start++;
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方最快:省去了反转时间
|
||||||
|
* 速度击败100%,内存击败74.78% 1ms
|
||||||
|
* @param s
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String reverseWords1(String s) {
|
||||||
|
char[] c = s.toCharArray();
|
||||||
|
char[] newC = new char[c.length + 1];
|
||||||
|
int i = c.length - 1;
|
||||||
|
int index = 0;
|
||||||
|
while(i >= 0){
|
||||||
|
while(i >= 0 && c[i] == ' ') --i;//删除前空格
|
||||||
|
int right = i;
|
||||||
|
while(i >= 0 && c[i] != ' ') --i;//找到第一个空格
|
||||||
|
//找到左右入口单词直接填入即可,剩下的单词类似于递归,继续重新开始上面的步骤
|
||||||
|
for(int left = i + 1; left <= right; ++left){
|
||||||
|
newC[index++] = c[left];
|
||||||
|
if(left == right){
|
||||||
|
newC[index++] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(index == 0){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return new String(newC, 0, index - 1);//左闭右开的
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,247 @@
|
||||||
|
package com.markilue.leecode.string.second;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.string.second
|
||||||
|
*@Author: dingjiawen
|
||||||
|
*@CreateTime: 2022-12-30 12:05
|
||||||
|
*@Description:
|
||||||
|
* TODO 二刷力扣28题 找出字符串中第一个匹配项的下标:
|
||||||
|
* 给你两个字符串 haystack 和 needle
|
||||||
|
* 请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。
|
||||||
|
* 如果 needle 不是 haystack 的一部分,则返回 -1 。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T06_StrStr {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
String haystack = "sadbutsad", needle = "sad";
|
||||||
|
System.out.println(strStr1(haystack, needle));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1() {
|
||||||
|
String haystack = "leetcode", needle = "leeto";
|
||||||
|
System.out.println(strStr(haystack, needle));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test2() {
|
||||||
|
String haystack = "hello", needle = "ll";
|
||||||
|
System.out.println(strStr(haystack, needle));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test3() {
|
||||||
|
String haystack = "mississippi", needle = "issip";
|
||||||
|
System.out.println(strStr(haystack, needle));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test4() {
|
||||||
|
String haystack = "ababaabbbbababbaabaaabaabbaaaabbabaabbbbbbabbaabbabbbabbbbbaaabaababbbaabbbabbbaabbbbaaabbababbabbbabaaabbaabbabababbbaaaaaaababbabaababaabbbbaaabbbabb", needle = "abbabbbabaa";
|
||||||
|
System.out.println(strStr3(haystack, needle));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:试试动态规划法:有问题,一旦匹配不上,后面就一直匹配不上了,虽然好像可以改状态转移方程,但是改完之后定义就变了
|
||||||
|
* TODO 动态规划五部曲:暂时有问题
|
||||||
|
* 1.dp定义: dp[i][j]表示使用haystack[0-j]能否匹配上needle[0-i]
|
||||||
|
* 2.dp状态转移方程:dp[i][j]有两种方式得到:使用haystack[j]和不使用haystack[j]
|
||||||
|
* 1.使用haystack[j]:现在刚匹配上
|
||||||
|
* dp[i][j]=!dp[i-1][j-2]&&dp[i-1][j-1]&&(haystack[j]==needle[i])
|
||||||
|
* 2.不使用haystack[j]:以前就匹配上了
|
||||||
|
* dp[i][j]=dp[i][j-1]
|
||||||
|
* 所以dp[i][j]=(!dp[i-1][j-2]&&dp[i-1][j-1]&&(haystack[j]==needle[i]))|| (dp[i][j-1])
|
||||||
|
* 3.dp初始化:为了方便初始化,将上述定义变为haystack[0-j-1]能否匹配上needle[0-i-1],那么dp[0][i]=true;dp[i][0]=false
|
||||||
|
* 4.dp遍历顺序:
|
||||||
|
* 5.dp举例推导:以haystack = "sadbutsad", needle = "sad"为例:
|
||||||
|
* [0 s a d b t s a d]
|
||||||
|
* i=0 t t t t t t t t t
|
||||||
|
* i=s f t t t t t t t t
|
||||||
|
* i=a f f t t t t t t t
|
||||||
|
* i=d f f f t t t t t t
|
||||||
|
* @param haystack
|
||||||
|
* @param needle
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int strStr(String haystack, String needle) {
|
||||||
|
|
||||||
|
boolean[][] dp = new boolean[needle.length() + 1][haystack.length() + 1];
|
||||||
|
//初始化
|
||||||
|
for (int i = 0; i < dp[0].length; i++) {
|
||||||
|
dp[0][i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < dp.length; i++) {
|
||||||
|
for (int j = 1; j < dp[0].length; j++) {
|
||||||
|
boolean flag = j - 2 >= 0 && i - 2 > 0 ? !dp[i - 1][j - 2] : true;
|
||||||
|
dp[i][j] = (flag && dp[i - 1][j - 1] && (haystack.charAt(j - 1) == needle.charAt(i - 1))) || (dp[i][j - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < dp[0].length; i++) {
|
||||||
|
if (dp[needle.length()][i]) {
|
||||||
|
return i - needle.length(); //找到了全匹配到的位置
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:尝试KMP算法。当出现字符串不匹配时,可以记录一部分之前已经匹配的文本内容,利用这些信息避免从头再去做匹配。
|
||||||
|
* 速度击败45.39%,内存击败5.21%
|
||||||
|
* @param haystack
|
||||||
|
* @param needle
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int strStr1(String haystack, String needle) {
|
||||||
|
if (needle == null || needle.length() == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int[] next = getNext1(needle);
|
||||||
|
int index = -1;//开始位置
|
||||||
|
|
||||||
|
for (int i = 0; i < haystack.length(); i++) {
|
||||||
|
while (index >= 0 && needle.charAt(index + 1) != haystack.charAt(i)) {
|
||||||
|
index = next[index];
|
||||||
|
}
|
||||||
|
if (needle.charAt(index + 1) == haystack.charAt(i)) {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
if (index == needle.length() - 1) {
|
||||||
|
return (i - needle.length() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;//没找到
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方获取next数组的方法:精髓在于这次的next[i]可以通过上一次的next[i-1]来获取,分为两种情况:
|
||||||
|
* 1)如果next[i-1]的下一个数和next[i]的下一个数相等,那么最大子串一定是在上一个的基础上+1,对应下面的if的内容
|
||||||
|
* 2)如果next[i-1]的下一个数和next[i]的下一个数不相等,那么寻找上一个最大子串,看看上一次最大子串的下一个数和next[i]的下一个数相等,如果不相等就寻找在上一次的,对应于下面的while内容
|
||||||
|
* 下所述的看就是用来记录上一次最大子串的索引
|
||||||
|
* @param needle
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int[] getNext1(String needle) {
|
||||||
|
int[] next = new int[needle.length()];
|
||||||
|
next[0] = -1;
|
||||||
|
int k = -1;
|
||||||
|
for (int i = 1; i < needle.length(); ++i) {
|
||||||
|
//神奇的是,k既是长度又是上一次不相等的索引
|
||||||
|
while (k != -1 && needle.charAt(k + 1) != needle.charAt(i)) {
|
||||||
|
k = next[k];
|
||||||
|
}
|
||||||
|
if (needle.charAt(k + 1) == needle.charAt(i)) {
|
||||||
|
++k;
|
||||||
|
}
|
||||||
|
next[i] = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方最快
|
||||||
|
* 速度击败100%,内存击败37.1% 0ms
|
||||||
|
* @param haystack
|
||||||
|
* @param needle
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int strStr2(String haystack, String needle) {
|
||||||
|
int n = haystack.length(), m = needle.length();
|
||||||
|
if (m == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int[] pi = new int[m];//next数组
|
||||||
|
for (int i = 1, j = 0; i < m; i++) {
|
||||||
|
while (j > 0 && needle.charAt(i) != needle.charAt(j)) {
|
||||||
|
j = pi[j - 1];
|
||||||
|
}
|
||||||
|
if (needle.charAt(i) == needle.charAt(j)) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
pi[i] = j;
|
||||||
|
}
|
||||||
|
for (int i = 0, j = 0; i < n; i++) {
|
||||||
|
while (j > 0 && haystack.charAt(i) != needle.charAt(j)) {
|
||||||
|
j = pi[j - 1];
|
||||||
|
}
|
||||||
|
if (haystack.charAt(i) == needle.charAt(j)) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if (j == m) {
|
||||||
|
return i - m + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自己尝试next不减1的做法
|
||||||
|
* 速度击败100%,内存击败70.85%
|
||||||
|
* @param haystack
|
||||||
|
* @param needle
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int strStr3(String haystack, String needle) {
|
||||||
|
int m = haystack.length();
|
||||||
|
int n = needle.length();
|
||||||
|
if (n == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//根据needle构造一个next数组,next[i]表示needle[0-i]的最长公共子串
|
||||||
|
int[] next = getNext(needle);
|
||||||
|
int index=0;
|
||||||
|
for (int i = 0; i < m; i++) {
|
||||||
|
while (index>0&&haystack.charAt(i)!=needle.charAt(index)){
|
||||||
|
index=next[index-1];//匹配不上就找上一个字母在哪重复的,看看之前重复的地方能不能匹配上
|
||||||
|
}
|
||||||
|
if(haystack.charAt(i)==needle.charAt(index)){
|
||||||
|
index++;//匹配上就试试下一个能不能匹配上
|
||||||
|
}
|
||||||
|
if(index==n){
|
||||||
|
//匹配到最末尾了
|
||||||
|
return i-index+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getNext(String needle) {
|
||||||
|
int index = 0;
|
||||||
|
int[] next = new int[needle.length()];
|
||||||
|
next[0] = 0;
|
||||||
|
char[] chars = needle.toCharArray();
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 1; i < next.length; i++) {
|
||||||
|
//如果匹配不上了
|
||||||
|
while (index != 0 && chars[i] != chars[index]){
|
||||||
|
//有趣的是:index既是最长公共子串长度,又是上一次匹配上的索引,所以能这样
|
||||||
|
index=next[index-1];//匹配不上就找上一个字母在哪重复的,看看之前重复的地方能不能匹配上
|
||||||
|
}
|
||||||
|
if(chars[i]==chars[index]){
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
next[i]=index;
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue