leecode更新

This commit is contained in:
markilue 2023-03-05 14:35:25 +08:00
parent b1eeb7c60c
commit f5a1d35d7c
2 changed files with 310 additions and 0 deletions

View File

@ -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[i1]=(s[i - 1] = \text{(}s[i1]=(也就是字符串形如 ()()()我们可以推出
* dp[i]=dp[i2]+2
* 2.s[i]=)s[i] = \text{)}s[i]=) s[i1]=)s[i - 1] = \text{)}s[i1]=)也就是字符串形如 ))))))我们可以推出 如果 s[idp[i1]1]=(s[i - \textit{dp}[i - 1] - 1] = \text{(}s[idp[i1]1]=(那么
* dp[i]=dp[i1]+dp[idp[i1]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;
}
}

View File

@ -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 在预先未知的某个下标 k0 <= 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;
}
}