leecode更新

This commit is contained in:
markilue 2022-12-30 18:15:26 +08:00
parent c1f0422617
commit 04c495fbb9
5 changed files with 457 additions and 2 deletions

View File

@ -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() {

View File

@ -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);
}
}

View File

@ -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() {

View File

@ -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);//左闭右开的
}
}
}

View File

@ -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;
}
}