leecode更新
This commit is contained in:
parent
b1eeb7c60c
commit
f5a1d35d7c
|
|
@ -0,0 +1,175 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-03-05 10:59
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣32题 最长有效括号:
|
||||||
|
* 给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T19_LongestValidParentheses {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
// String s = "(())";
|
||||||
|
// String s = "()()";
|
||||||
|
// String s = "(()())";
|
||||||
|
// String s = ")(((((()())()()))()(()))(";
|
||||||
|
String s = ")())";
|
||||||
|
// String s = "()(()";
|
||||||
|
System.out.println(longestValidParentheses3(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:其实就是将有效括号 进一步变为了寻找最长,那么可以使用动态规划法
|
||||||
|
* TODO DP五部曲:
|
||||||
|
* 1.dp定义: dp[i][j]表示 以i结尾以j开头的子串 是不是有效括号
|
||||||
|
* 2.dp状态转移方程:
|
||||||
|
* 1. s[i]匹配得上s[j]
|
||||||
|
* dp[i][j]=dp[i-1][j+1]
|
||||||
|
* 3.dp初始化: 为了初始化方便 s[i] s[j]变为s[i-1] dp[i][j]=true
|
||||||
|
* 4.dp遍历顺序:从上到下
|
||||||
|
* 5.dp举例推导:
|
||||||
|
* 暂时有问题
|
||||||
|
* @param s
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int longestValidParentheses(String s) {
|
||||||
|
|
||||||
|
char[] chars = s.toCharArray();
|
||||||
|
|
||||||
|
boolean[][] dp = new boolean[chars.length][chars.length];
|
||||||
|
int maxLength = 0;
|
||||||
|
for (int i = 0; i < chars.length; i++) {
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
if (isMatch(chars, i, j)) {
|
||||||
|
if (i == j + 1) {
|
||||||
|
dp[i][j] = true;
|
||||||
|
} else {
|
||||||
|
dp[i][j] = dp[i - 1][j + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断他前后是不是也能匹配上()()的情况
|
||||||
|
if (dp[i][j]) {
|
||||||
|
int start = j;
|
||||||
|
for (int k = j - 1; k >= 0; k--) {
|
||||||
|
if (dp[j - 1][k]) {
|
||||||
|
dp[i][k] = true;//修复,对应的位置
|
||||||
|
start = k;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}//找起始位置
|
||||||
|
if (maxLength < i - start + 1) maxLength = i - start + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxLength;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMatch(char[] chars, int i, int j) {
|
||||||
|
return chars[i] == ')' && chars[j] == '(';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仍然使用stack记录法
|
||||||
|
* 暂时有问题
|
||||||
|
* @param s
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int longestValidParentheses1(String s) {
|
||||||
|
|
||||||
|
char[] chars = s.toCharArray();
|
||||||
|
|
||||||
|
int maxLength = 0;
|
||||||
|
int curLength = 0;
|
||||||
|
|
||||||
|
Stack<Character> stack = new Stack<>();
|
||||||
|
|
||||||
|
for (char aChar : chars) {
|
||||||
|
if (aChar == '(') {
|
||||||
|
stack.push(aChar);
|
||||||
|
} else {
|
||||||
|
if (!stack.isEmpty()) {
|
||||||
|
stack.pop();
|
||||||
|
curLength += 2;
|
||||||
|
if (maxLength < curLength) maxLength = curLength;
|
||||||
|
} else {
|
||||||
|
stack.clear();
|
||||||
|
curLength = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return maxLength;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方动态规划法:
|
||||||
|
* TODO
|
||||||
|
* 1.s[i]=‘)’ 且 s[i−1]=‘(’s[i - 1] = \text{‘(’}s[i−1]=‘(’,也就是字符串形如 “……()”“……()”“……()”,我们可以推出:
|
||||||
|
* dp[i]=dp[i−2]+2
|
||||||
|
* 2.s[i]=‘)’s[i] = \text{‘)’}s[i]=‘)’ 且 s[i−1]=‘)’s[i - 1] = \text{‘)’}s[i−1]=‘)’,也就是字符串形如 “……))”“……))”“……))”,我们可以推出: 如果 s[i−dp[i−1]−1]=‘(’s[i - \textit{dp}[i - 1] - 1] = \text{‘(’}s[i−dp[i−1]−1]=‘(’,那么
|
||||||
|
* dp[i]=dp[i−1]+dp[i−dp[i−1]−2]+2
|
||||||
|
* @param s
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int longestValidParentheses2(String s) {
|
||||||
|
int maxans = 0;
|
||||||
|
int[] dp = new int[s.length()];
|
||||||
|
for (int i = 1; i < s.length(); i++) {
|
||||||
|
if (s.charAt(i) == ')') {
|
||||||
|
if (s.charAt(i - 1) == '(') {
|
||||||
|
dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
|
||||||
|
} else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
|
||||||
|
dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2;
|
||||||
|
}
|
||||||
|
maxans = Math.max(maxans, dp[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxans;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方栈法:存入栈的是位置
|
||||||
|
* @param s
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int longestValidParentheses3(String s) {
|
||||||
|
int maxans = 0;
|
||||||
|
Deque<Integer> stack = new LinkedList<Integer>();
|
||||||
|
stack.push(-1);
|
||||||
|
for (int i = 0; i < s.length(); i++) {
|
||||||
|
if (s.charAt(i) == '(') {
|
||||||
|
stack.push(i);
|
||||||
|
} else {
|
||||||
|
stack.pop();
|
||||||
|
if (stack.isEmpty()) {
|
||||||
|
stack.push(i);
|
||||||
|
} else {
|
||||||
|
maxans = Math.max(maxans, i - stack.peek());//只peek不pop是关键
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxans;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
package com.markilue.leecode.hot100;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.hot100
|
||||||
|
*@Author: markilue
|
||||||
|
*@CreateTime: 2023-03-05 13:45
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣33题 搜索旋转排序数组:
|
||||||
|
* 整数数组 nums 按升序排列,数组中的值 互不相同 。
|
||||||
|
* 在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,
|
||||||
|
* 使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。
|
||||||
|
* 例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
|
||||||
|
* 给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
|
||||||
|
* 你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T20_Search {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
int[] nums = {4, 5, 6, 7, 0, 1, 2};
|
||||||
|
int target = 3;
|
||||||
|
System.out.println(search(nums, target));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1() {
|
||||||
|
int[] nums = {1, 3};
|
||||||
|
int target = 3;
|
||||||
|
System.out.println(search(nums, target));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test2() {
|
||||||
|
int[] nums = {5,1, 3};
|
||||||
|
int target = 1;
|
||||||
|
System.out.println(search(nums, target));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路: 难度自然在于 设计一个时间复杂度为O(log n)的算法
|
||||||
|
* 时间复杂度logn则必然是考虑二分搜索 因为旋转后的数一定是小于第1个数
|
||||||
|
* 1.先找具体旋转的位置(二分法)
|
||||||
|
* 2.再分为两个区具体去找
|
||||||
|
* 速度击败100% 内存击败42.71%
|
||||||
|
* @param nums
|
||||||
|
* @param target
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int search(int[] nums, int target) {
|
||||||
|
if (nums.length == 1) {
|
||||||
|
return nums[0] == target ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int k = searchK(nums, 0, nums.length - 1, nums[0]);
|
||||||
|
if (target < nums[0] || k == 0) {
|
||||||
|
if (target < nums[k]) return -1;
|
||||||
|
return binarySearchTrue(nums, k, nums.length - 1, target);
|
||||||
|
} else {
|
||||||
|
return binarySearchTrue(nums, 0, k - 1, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int searchK(int[] nums, int start, int end, int target) {
|
||||||
|
if (start == end) {
|
||||||
|
if (nums[start] < target) return start;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int mid = start + ((end - start) >> 1);
|
||||||
|
if (nums[mid] < target) {
|
||||||
|
return searchK(nums, start, mid, target);
|
||||||
|
} else {
|
||||||
|
return searchK(nums, mid + 1, end, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int binarySearchTrue(int[] nums, int start, int end, int target) {
|
||||||
|
if (start > end) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int mid = start + ((end - start) >> 1);
|
||||||
|
if (nums[mid] < target) {
|
||||||
|
return binarySearchTrue(nums, mid + 1, end, target);
|
||||||
|
} else if (nums[mid] > target) {
|
||||||
|
return binarySearchTrue(nums, start, mid - 1, target);
|
||||||
|
} else {
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方二分查找:将两次二分合并在一起;就是增加了一层判断:nums[0]和nums[mid]得到关系
|
||||||
|
* 速度击败100% 内存击败37.71%
|
||||||
|
* @param nums
|
||||||
|
* @param target
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int search1(int[] nums, int target) {
|
||||||
|
int n = nums.length;
|
||||||
|
if (n == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (n == 1) {
|
||||||
|
return nums[0] == target ? 0 : -1;
|
||||||
|
}
|
||||||
|
int l = 0, r = n - 1;
|
||||||
|
while (l <= r) {
|
||||||
|
int mid = (l + r) / 2;
|
||||||
|
if (nums[mid] == target) {
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
|
if (nums[0] <= nums[mid]) {
|
||||||
|
if (nums[0] <= target && target < nums[mid]) {
|
||||||
|
r = mid - 1;
|
||||||
|
} else {
|
||||||
|
l = mid + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (nums[mid] < target && target <= nums[n - 1]) {
|
||||||
|
l = mid + 1;
|
||||||
|
} else {
|
||||||
|
r = mid - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue