3.29 二分查找+栈

This commit is contained in:
zhangsan 2025-03-30 15:37:13 +08:00
parent a41a72c55b
commit 282edf97ec
6 changed files with 196 additions and 1 deletions

View File

@ -0,0 +1,53 @@
package binary_search;
/**
* 题目 153. 寻找旋转排序数组中的最小值 (findMin)
* 描述已知一个长度为 n 的数组预先按照升序排列经由 1 n 旋转 得到输入数组例如原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到
* 若旋转 4 则可以得到 [4,5,6,7,0,1,2]
* 若旋转 7 则可以得到 [0,1,2,4,5,6,7]
* 注意数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]]
* 给你一个元素值 互不相同 的数组 nums 它原来是一个升序排列的数组并按上述情形进行了多次旋转请你找出并返回数组中的 最小元素
* 你必须设计一个时间复杂度为 O(log n) 的算法解决此问题
* <p>
* 示例 1
* 输入nums = [3,4,5,1,2]
* 输出1
* 解释原数组为 [1,2,3,4,5] 旋转 3 次得到输入数组
* <p>
* 链接https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/
*/
public class FindMin {
/**
* 判断区间是否已经有序
*
* 如果当前区间 left right是有序的 nums[left] < nums[right]说明这个区间没有发生旋转最小值一定是区间的第一个元素 nums[left]所以直接返回它
* 计算中间索引
*
* 使用 int mid = left + (right - left) / 2; 计算中间索引避免直接相加可能造成的溢出问题
* 判断最小值在哪个区间
*
* 左侧有序情况如果 nums[mid] >= nums[left]说明从 left mid 是有序的此时最小值不可能出现在有序部分所以最小值一定在右半部分因此更新 left = mid + 1
* 旋转点在左侧情况如果 nums[mid] < nums[left]说明中间部分处于旋转状态即最小值可能出现在左半部分或就是 nums[mid]因此将 right 更新为 mid
* 退出条件
*
* 循环在 left == right 时退出此时 nums[left] 就是整个数组的最小值
* @param nums
* @return
*/
public int findMin(int[] nums) {
int left = 0, right = nums.length - 1;
while (left < right) {
if (nums[left] < nums[right]) {
return nums[left];
}
int mid = left + (right - left) / 2;
if (nums[mid] >= nums[left]) {
left = mid + 1;
} else {
right = mid;
}
}
return nums[left];
}
}

View File

@ -1,6 +1,6 @@
package binary_search; package binary_search;
/** /**
* 题目 33. 搜索旋转排序数组 (searchRange) * 题目 33. 搜索旋转排序数组 (search)
* 描述整数数组 nums 按升序排列数组中的值 互不相同 * 描述整数数组 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 在预先未知的某个下标 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 * 给你 旋转后 的数组 nums 和一个整数 target 如果 nums 中存在这个目标值 target 则返回它的下标否则返回 -1

View File

@ -0,0 +1,19 @@
package stack;
/**
* 题目 394. 字符串解码 (decodeString)
* 描述给定一个经过编码的字符串返回它解码后的字符串
* 编码规则为: k[encoded_string]表示其中方括号内部的 encoded_string 正好重复 k 注意 k 保证为正整数
* 你可以认为输入字符串总是有效的输入字符串中没有额外的空格且输入的方括号总是符合格式要求的
* 此外你可以认为原始数据不包含数字所有的数字只表示重复的次数 k 例如不会出现像 3a 2[4] 的输入
* 示例 1
输入s = "3[a]2[bc]"
输出"aaabcbc"
* 链接https://leetcode.cn/problems/search-in-rotated-sorted-array/
*/
public class DecodeString {
public String decodeString(String s) {
return "";
}
}

View File

@ -0,0 +1,51 @@
package stack;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
/**
* 题目 20. 有效的括号 (isValid)
* 描述给定一个只包括 '('')''{''}''['']' 的字符串 s 判断字符串是否有效
*
* 有效字符串需满足
*
* 左括号必须用相同类型的右括号闭合
* 左括号必须以正确的顺序闭合
* 每个右括号都有一个对应的相同类型的左括号
*
* 链接https://leetcode.cn/problems/valid-parentheses/
*/
public class IsValid {
public boolean isValid(String s) {
// 如果长度为奇数直接返回 false
int sz = s.length();
if (sz % 2 == 1) return false;
// 映射括号
HashMap<Character, Character> map = new HashMap<>();
map.put('(', ')');
map.put('[', ']');
map.put('{', '}');
Deque<Character> stack = new ArrayDeque<>();
for (int i = 0; i < sz; i++) {
char cur = s.charAt(i);
// 如果是左括号压入栈
if (map.containsKey(cur)) {
stack.push(cur);
}
// 如果是右括号检查栈顶是否是匹配的左括号
else {
if (stack.isEmpty() || map.get(stack.pop()) != cur) {
return false;
}
}
}
// 最后栈应为空
return stack.isEmpty();
}
}

View File

@ -0,0 +1,56 @@
package stack;
import java.util.Stack;
/**
* 题目 155. 最小栈 (MinStack)
* 描述设计一个支持 push pop top 操作并能在常数时间内检索到最小元素的栈
*
* 实现 MinStack :
* MinStack() 初始化堆栈对象
* void push(int val) 将元素val推入堆栈
* void pop() 删除堆栈顶部的元素
* int top() 获取堆栈顶部的元素
* int getMin() 获取堆栈中的最小元素
*
* 链接https://leetcode.cn/problems/min-stack/description/
*/
public class MinStack {
private Stack<Integer> stack; // 主栈
private Stack<Integer> minStack; // 辅助栈存储每个阶段的最小值
public MinStack() {
stack = new Stack<>();
minStack = new Stack<>();
}
// 向栈中压入一个值
public void push(int val) {
stack.push(val);
// 如果辅助栈为空或者当前值比辅助栈的栈顶元素还小压入辅助栈
if (minStack.isEmpty() || val <= minStack.peek()) {
minStack.push(val);
}
}
// 弹出栈顶元素
public void pop() {
// 弹出主栈的栈顶元素
int poppedValue = stack.pop();
// 如果弹出的元素是当前最小值则同时弹出辅助栈的栈顶元素
if (poppedValue == minStack.peek()) {
minStack.pop();
}
}
// 获取栈顶元素
public int top() {
return stack.peek();
}
// 获取当前栈中的最小值
public int getMin() {
return minStack.peek();
}
}

View File

@ -0,0 +1,16 @@
package stack;
import org.junit.Test;
import static org.junit.Assert.*;
public class DecodeStringTest {
@Test
public void decodeString() {
String s = "3[a]2[bc]";
DecodeString solution = new DecodeString();
String res=solution.decodeString(s);
System.out.println(res);
}
}