leecode更新

This commit is contained in:
markilue 2022-12-28 12:57:06 +08:00
parent f3e88db25c
commit c1f0422617
10 changed files with 598 additions and 4 deletions

View File

@ -0,0 +1,88 @@
package com.markilue.leecode.hashtable;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.hashtable
*@Author: dingjiawen
*@CreateTime: 2022-12-28 10:12
*@Description:
* TODO 力扣383题 赎金信:
* 给你两个字符串ransomNote magazine 判断 ransomNote 能不能由 magazine 里面的字符构成
* 如果可以返回 true 否则返回 false
* magazine 中的每个字符只能在 ransomNote 中使用一次
*@Version: 1.0
*/
public class T06_CanConstruct {
/**
* 思路本质上还是和第一题同素异形类似记录字母出现的次数只不过允许多不允许少
* 速度击败99.88%内存击败76.12%
* @param ransomNote
* @param magazine
* @return
*/
public boolean canConstruct(String ransomNote, String magazine) {
char[] mChars = magazine.toCharArray();
char[] rChars = ransomNote.toCharArray();
int[] map = new int[26];//数组当map用
for (char mChar : mChars) {
map[mChar-'a']++;
}
for (char rChar : rChars) {
map[rChar-'a']--;
}
for (int i : map) {
if(i<0){
return false;
}
}
return true;
}
/**
* 思路浅优化判断可以在第二个for就开始
* 速度击败99.88%内存击败71.7%
* @param ransomNote
* @param magazine
* @return
*/
public boolean canConstruct2(String ransomNote, String magazine) {
char[] mChars = magazine.toCharArray();
char[] rChars = ransomNote.toCharArray();
int[] map = new int[26];//数组当map用
for (char mChar : mChars) {
map[mChar-'a']++;
}
for (char rChar : rChars) {
map[rChar-'a']--;
if(map[rChar-'a']<0){
return false;
}
}
return true;
}
/**
* 官方最快记录这次找到的位置,如果下次要找相同的字符只能从这次的后面开始找
* 时间复杂度是不是要高一些本质上取决于indexOf的时间复杂度
* 速度击败100%内存击败96.44%
* @param ransomNote
* @param magazine
* @return
*/
public boolean canConstruct1(String ransomNote, String magazine) {
int[] charIndex = new int[26];
for (char c : ransomNote.toCharArray()) {
int p = magazine.indexOf(c, charIndex[c - 'a']);//indexOf(char,fromIndex)
if(p == -1) return false;
charIndex[c - 'a'] = p + 1;//如果下次要找相同的字符只能从这次的后面开始找
}
return true;
}
}

View File

@ -17,7 +17,7 @@ import java.util.List;
* 注意答案中不可以包含重复的三元组
* @Version: 1.0
*/
public class ThreeSum {
public class T07_ThreeSum {
/**
* 这道题使用哈希法的思路:

View File

@ -17,7 +17,7 @@ import java.util.*;
* 你可以按 任意顺序 返回答案
* @Version: 1.0
*/
public class FourSum {
public class T08_FourSum {
@Test
public void test() {

View File

@ -0,0 +1,116 @@
package com.markilue.leecode.hashtable.second;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.hashtable.second
*@Author: dingjiawen
*@CreateTime: 2022-12-28 10:30
*@Description:
* TODO 二刷15题 三数之和:
* 给你一个整数数组 nums 判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k j != k
* 同时还满足 nums[i] + nums[j] + nums[k] == 0
* 你返回所有和为 0 且不重复的三元组
* 注意答案中不可以包含重复的三元组
*@Version: 1.0
*/
public class T07_ThreeSum {
@Test
public void test(){
int[] nums = {-1, 0, 1, 2, -1, -4};
System.out.println(threeSum(nums));
}
/**
* 思路:这题本质上是一个O(N^3)的一个暴力解法,考虑一层for放外面,里面用hashMap记录将复杂度变为O(N^2)
* 由于对于结果不考虑index只考虑具体的数,因此考虑先对数组进行排序
* 速度击败47.14%内存击败84.92% 22ms
* 增加第一个数大于0则一定不可能了的判断以后 速度击败75.68%内存击败80.11% 20ms
* @param nums
* @return
*/
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
if (nums.length < 3) {
return result;
}
Arrays.sort(nums);//排序
for (int i = 0; i < nums.length - 2; i++) {
//第一个数大于0则一定不可能了
if(nums[i]>0){
break;
}
//避免重复
if(i>0&&nums[i]==nums[i-1]){
continue;
}
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
int sum = nums[left] + nums[right];
if (sum > -nums[i]){
//整体大于0
right--;
}else if(sum<-nums[i]){
//整体小于0
left++;
}else {
//刚刚好
result.add(new ArrayList<>(Arrays.asList(nums[i],nums[left],nums[right])));
left++;
right--;
//由于不能重复三元组,所以需要多偏移
while (left<right&&nums[left-1]==nums[left])left++;
while (left<right&&nums[right]==nums[right+1])right--;
}
}
}
return result;
}
/**
* 官方最快9ms
* 但是与本人几乎完全一致所以经过测试是电脑原因
* @param nums
* @return
*/
public List<List<Integer>> threeSum1(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if(nums.length < 3) return res;
Arrays.sort(nums);
for(int i=0;i<nums.length-2;i++){
if (i == 0 || (i > 0 && nums[i] != nums[i-1])) {
int j = i+1;
int k = nums.length-1;
while(j<k){
if(nums[i]+nums[j]+nums[k]==0){
List<Integer> cur = new ArrayList<Integer>();
cur.add(nums[i]);
cur.add(nums[j]);
cur.add(nums[k]);
res.add(cur);
while(j<k && nums[j]==nums[j+1])j++;
while(j<k && nums[k]==nums[k-1])k--;
j++;
k--;
}else if(nums[i]+nums[j]+nums[k] > 0) k--;
else j++;
}
}
}
return res;
}
}

View File

@ -0,0 +1,163 @@
package com.markilue.leecode.hashtable.second;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.hashtable.second
*@Author: dingjiawen
*@CreateTime: 2022-12-28 11:16
*@Description:
* TODO 二刷力扣18题 四数之和:
* 给你一个由 n 个整数组成的数组 nums 和一个目标值 target
* 请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]]
* 若两个四元组元素一一对应则认为两个四元组重复
* 0 <= a, b, c, d < n
* abc d 互不相同
* nums[a] + nums[b] + nums[c] + nums[d] == target
* 你可以按 任意顺序 返回答案
*@Version: 1.0
*/
public class T08_FourSum {
@Test
public void test() {
int[] nums = {1, 0, -1, 0, -2, 2};
int target = 0;
System.out.println(fourSum(nums, target));
}
@Test
public void test1() {
int[] nums = {2, 2, 2, 2, 2};
int target = 8;
System.out.println(fourSum(nums, target));
}
@Test
public void test2() {
int[] nums = {1, -2, -5, -4, -3, 3, 3, 5};
int target = -11;
System.out.println(fourSum(nums, target));
}
/**
* 思路:在三数之和外面再加上一层for,时间复杂度O(N^3)
* 熟读击败49.87%内存击败71.72%
* @param nums
* @param target
* @return
*/
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result = new ArrayList<>();
if (nums.length < 4) {
return result;
}
Arrays.sort(nums);
for (int i = 0; i < nums.length - 3; i++) {
if (nums[i] > 0 && nums[i] > target) break;
if (i > 0 && nums[i] == nums[i - 1]) continue;
for (int j = i + 1; j < nums.length - 2; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) continue;
int left = j + 1;
int right = nums.length - 1;
while (left < right) {
long sum = (long) target - nums[left] - nums[right];
if (sum < nums[i] + nums[j]) {
//整体大于target
right--;
} else if (sum > nums[i] + nums[j]) {
//整体小于target
left++;
} else {
//刚刚好
result.add(new ArrayList<>(Arrays.asList(nums[i], nums[j], nums[left], nums[right])));
left++;
right--;
while (left < right && nums[left - 1] == nums[left]) left++;
while (left < right && nums[right + 1] == nums[right]) right--;
}
}
}
}
return result;
}
/**
* 官方最快2ms
* 与本人一致多了几个考验功力的减枝操作
* @param nums
* @param target
* @return
*/
public List<List<Integer>> fourSum1(int[] nums, int target) {
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
int length = nums.length;
for (int i = 0; i < length - 3; i++) {
// 跳过重复值
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
// 最小合都大于目标值说明无解
if ((long) nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
//太大了
break;
}
// 最大合小于目标值说明i太小了继续后移
if ((long) nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {
//太小了
continue;
}
for (int j = i + 1; j < length - 2; j++) {
// 跳过重复的数字
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
// 最小合都大于目标值说明无解
if ((long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
break;
}
// 最大合小于目标值说明i太小了继续后移
if ((long) nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
int left = j + 1, right = length - 1;
while (left < right) {
int x = nums[left], y = nums[right];
int sum = nums[i] + nums[j] + x + y;
if (sum == target) {
res.add(Arrays.asList(nums[i], nums[j], x, y));
// 将两个指针都往中间推移遇到重复的数字就跳过
left++;
while (left < right && nums[left] == nums[left - 1]) {
left++;
}
right--;
while (left < right && nums[right] == nums[right + 1]) {
right--;
}
} else if (sum < target) {
// 和小于目标值因为是排序过的要想结果变大左标就要往右移动数字更大
left++;
} else {
// 同理和大于目标值右标就要往左移动数字更小
right--;
}
}
}
}
return res;
}
}

View File

@ -14,7 +14,7 @@ import org.junit.Test;
*
* @Version: 1.0
*/
public class ReverseString {
public class T01_ReverseString {
@Test
public void test(){

View File

@ -13,7 +13,7 @@ import org.junit.Test;
* 2)如果剩余字符小于 2k 但大于或等于 k 则反转前 k 个字符其余字符保持原样
* @Version: 1.0
*/
public class ReverseStr {
public class T02_ReverseStr {
@Test
public void test() {

View File

@ -0,0 +1,77 @@
package com.markilue.leecode.string;
import org.junit.Test;
import java.util.Arrays;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.string
*@Author: dingjiawen
*@CreateTime: 2022-12-28 12:41
*@Description:
* TODO 剑指offer05 替换空格:
*
*@Version: 1.0
*/
public class T03_ReplaceSpace {
@Test
public void test(){
String s = "We are happy.";
System.out.println(replaceSpace(s));
}
/**
* 思路使用额外的辅助空间build进行构造
* 速度击败100%内存击败36.8%
* @param s
* @return
*/
public String replaceSpace(String s) {
StringBuilder builder = new StringBuilder();
char[] chars = s.toCharArray();
for (char aChar : chars) {
if(' '==aChar){
builder.append("%20");
}else {
builder.append(aChar);
}
}
return builder.toString();
}
/**
* 双指针法:不使用额外的空间首先将原来的进行扩容
* 速度击败100%内存击败20.93%
* @param s
* @return
*/
public String replaceSpace1(String s) {
int count = 0; // 统计空格的个数
int sOldSize = s.length();
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == ' ') {
count++;
}
}
// 扩充字符串s的大小也就是每个空格替换成"%20"之后的大小
char[] chars = Arrays.copyOf(s.toCharArray(), s.length() + count * 2);
int sNewSize = chars.length;
// 从后先前将空格替换为"%20"
for (int i = sNewSize - 1, j = sOldSize - 1; j < i; i--, j--) {
if (chars[j] != ' ') {
chars[i] = chars[j];
} else {
chars[i] = '0';
chars[i - 1] = '2';
chars[i - 2] = '%';
i -= 2;
}
}
return new String(chars);
}
}

View File

@ -0,0 +1,87 @@
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-28 12:00
*@Description:
* TODO 二刷力扣344题 反转字符串:
* 编写一个函数其作用是将输入的字符串反转过来输入字符串以字符数组 s 的形式给出
* 不要给另外的数组分配额外的空间你必须原地修改输入数组使用 O(1) 的额外空间解决这一问题
*@Version: 1.0
*/
public class T01_ReverseString {
@Test
public void test(){
char[] s = {'h', 'e', 'l', 'l', 'o'};
reverseString(s);
System.out.println(Arrays.toString(s));
}
/**
* 思路:两头指针分别对换
* 速度击败100%内存击败15.55%
* @param s
*/
public void reverseString(char[] s) {
int left=0;
int right=s.length-1;
while (left<right){
exchange(s,left,right);
left++;
right--;
}
}
public void exchange(char[] s,int left,int right){
char temp=s[left];
s[left]=s[right];
s[right]=temp;
}
/**
* temp提出减少内存
* @param s
*/
public void reverseString1(char[] s) {
if (s.length<=1) {
return;
}
char temp;
for (int i = 0; i < s.length / 2; i++) {
temp=s[i];
s[i]=s[s.length-1-i];
s[s.length-1-i]=temp;
}
}
/**
* 官方位运算交换
* 速度击败100%内存击败67.99%
* @param s
*/
public void reverseString2(char[] s) {
int l = 0;
int r = s.length - 1;
while (l < r) {
s[l] ^= s[r]; //构造 a ^ b 的结果并放在 a
s[r] ^= s[l]; // a ^ b 这一结果再 ^ b 存入b中此时 b = a, a = a ^ b
s[l] ^= s[r]; //a ^ b 的结果再 ^ a 存入 a 此时 b = a, a = b 完成交换
l++;
r--;
}
}
}

View File

@ -0,0 +1,63 @@
package com.markilue.leecode.string.second;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.string.second
*@Author: dingjiawen
*@CreateTime: 2022-12-28 12:22
*@Description:
* TODO 二刷力扣541题 反转字符串 II
* 给定一个字符串 s 和一个整数 k从字符串开头算起每计数至 2k 个字符就反转这 2k 字符中的前 k 个字符
* 1)如果剩余字符少于 k 则将剩余字符全部反转
* 2)如果剩余字符小于 2k 但大于或等于 k 则反转前 k 个字符其余字符保持原样
*@Version: 1.0
*/
public class T02_ReverseStr {
@Test
public void test(){
String s = "abcdefg";
int k = 2;
System.out.println(reverseStr(s,k));
}
@Test
public void test1(){
String s = "abcdef";
int k = 2;
System.out.println(reverseStr(s,k));
}
/**
* 速度击败100%内存击败25.83%
* @param s
* @param k
* @return
*/
public String reverseStr(String s, int k) {
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length; i+=2*k) {
if(i+k> chars.length-1){
reverse(chars,i, chars.length-1);
}else {
reverse(chars,i,i+k-1);
}
}
return new String(chars);
}
public void reverse(char[] s, int startIndex,int endIndex) {
char temp;
while (startIndex<endIndex){
temp=s[startIndex];
s[startIndex]=s[endIndex];
s[endIndex]=temp;
startIndex++;
endIndex--;
}
}
}