记录Leetcode热题100的刷题历程,遇到理解不易的题目我会在题目下方做好详细题解及其解决方案的分析。欢迎关注,一起进步,提高基本功。
示例 1:
输入:s = “3[a]2[bc]”
输出:“aaabcbc”
示例 2:
输入:s = “3[a2[c]]”
输出:“accaccacc”
class Solution{
public String decodeString(String s) {
StringBuilder res = new StringBuilder();
int multi = 0;
LinkedList<Integer> stackMutil = new LinkedList<>();
LinkedList<String> stackRes = new LinkedList<>();
for (Character c :
s.toCharArray()) {
// char 为数字时,将数字字符转化为数字 multi,用于后续倍数计算;
if (c >= '0' && c <= '9'){
System.out.println(" ============= c为数字");
multi = multi * 10 + Integer.parseInt(c + "");
System.out.println("multi = " + multi);
}else if (c == '['){//当 c 为 [ 时,将当前 multi 和 res 入栈,并分别置空置
System.out.println(" ============= c 为 [");
stackRes.addLast(res.toString());
stackMutil.addLast(multi);
System.out.println("stackRes = " + Arrays.toString(stackRes.toArray()));
System.out.println("stackMutil = " + Arrays.toString(stackMutil.toArray()));
//清空
multi = 0;
res = new StringBuilder();
}else if (c == ']'){//当 c 为 ] 时,stack 出栈,拼接字符串 res = last_res + cur_multi * res
System.out.println(" ============= c 为 ]");
Integer mutil = stackMutil.removeLast();
StringBuilder tempStr = new StringBuilder();
for (int i = 0; i < mutil; i++) {
tempStr.append(res);
}
System.out.println("tempStr = " + tempStr);
res = new StringBuilder(stackRes.removeLast() + tempStr);
System.out.println("res = " + res.toString());
}else {
System.out.println(" ============= c 为字符");
res.append(c);
System.out.println("res = " + res.toString());
}
}
return res.toString();
}
}
输入:
"3[a2[c]]"
输出:
multi = 3
============= c 为 [
stackRes = []
stackMutil = [3]
============= c 为字符
res = a
============= c为数字
multi = 2
============= c 为 [
stackRes = [, a]
stackMutil = [3, 2]
============= c 为字符
res = c
============= c 为 ]
tempStr = cc
res = acc
============= c 为 ]
tempStr = accaccacc
res = accaccacc
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
class Solution {
public int maxSubArray(int[] nums) {
if (nums.length == 0) return 0;
int n = nums.length;
//以 nums[i] 为结尾的「最大子数组和」为 dp[i]。
int[] dp = new int[n];
dp[0] = nums[0];
for (int i = 1/*注意,不是以i = 0开头*/; i < n; i++) {
//最大值有两个选择,nums[i],或者 nums[i] + 前面的最大子数组和
dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
}
//寻找最大值
int res = Integer.MIN_VALUE;
for (int i = 0; i < n; i++) {
res = Math.max(res, dp[i]);
}
return res;
}
}
给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。子数组是数组中元素的连续非空序列。 示例 1:输入:nums = [1,1,1], k = 2
输出:2
class Solution {
public int subarraySum(int[] nums, int k) {
int count = 0;
int prefix = 0;
HashMap<Integer, Integer> hashMap = new HashMap<>();
hashMap.put(0, 1);//key = 前缀和, value = 前缀和的出现的次数
for (int i = 0; i < nums.length; i++) {
prefix += nums[i];
//检查哈希表中是否存在键prefix - k,如果存在,说明之前的前缀和中有某个子数组的和等于k - prefix,这意味着从那个子数组到当前
//位置的子数组和为k。因此,将count增加哈希表中键为pre - k的值。
if (hashMap.containsKey(prefix - k)){
count += hashMap.get(prefix - k);
}
//存储每个prefix及其数量到hashmap中
hashMap.put(prefix,hashMap.getOrDefault(prefix,0) + 1);
}
return count;
}
}
前缀和的优势:以(o1)的时间复杂度得到某块区间的总和。
前缀和(Prefix Sum)是一种在计算中经常使用的技巧,用于有效地计算数组中某一范围内元素的和。前缀和的基本思想是创建一个新的数组,其中每个元素表示原始数组中前若干个元素的累加和。
假设有一个数组 arr
,前缀和数组 prefixSum
的第 i
个元素 prefixSum[i]
表示原数组 arr
中前 i
个元素的和。具体而言,prefixSum[i]
等于 arr[0] + arr[1] + ... + arr[i]
。
使用前缀和的好处是,在计算任意区间 [left, right]
内元素的和时,你只需要执行一次减法操作,即 prefixSum[right] - prefixSum[left - 1]
(注意要处理 left
为0的情况)。这比遍历区间内的元素并逐个相加要高效得多,尤其在需要多次查询不同区间和的情况下。
前缀和在处理数组或序列的部分和问题(如子数组和、区间和、累积和)非常有用,常见的应用包括解决子数组和等于特定值的问题,以及在一维和二维数组中进行区间和的快速查询。
/**
* @author linshujie
*/
public class PrefixSum {
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4, 5 };
int n = arr.length;
prefixSum(arr, n);
}
private static void prefixSum(int[] arr, int n) {
// 创建一个数组来存储前缀和
int[] prefixSum = new int[n];
// 计算前缀和并存储在prefixSum数组中
prefixSum[0] = arr[0];
for (int i = 1; i < n; i++) {
prefixSum[i] = prefixSum[i - 1] + arr[i];
}
// 输出前缀和数组
System.out.println("Prefix Sum Array:");
for (int i = 0; i < n; i++) {
System.out.print(prefixSum[i] + " ");
}
}
}
int left = 0, right = 0;
while (left < right && right < s.size()) {
// 增大窗口
window.add(s[right]);
right++;
while (window needs shrink) {
// 缩小窗口
window.remove(s[left]);
left++;
}
}
class Solution {
public int slideWindow(String s) {
//选择合适数据结构作为window
Map<Character, Integer> window = new HashMap<>();
int left = 0, right = 0, res = 0;
while (right < s.length()) {//右边界
//扩大窗口
char cRight = s.charAt(right);
hashMap.put(cRight, hashMap.getOrDefault(cRight, 0) + 1);//记录c的数量
right++;
//打印,查看算法执行情况,便于调整细节
// System.out.println("left = " + left + " right = " + right);
//缩小窗口
while (/*满足条件*/) {
char cLeft = s.charAt(left);
hashMap.put(cLeft,hashMap.get(cLeft) - 1);
left++;
}
//更新窗口最新数据
...
}
return res;
}
}
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1:输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
class Solution {
public int lengthOfLongestSubstring(String s) {
Map<Character, Integer> hashMap = new HashMap<>();
int left = 0, right = 0, res = 0;
while (right < s.length()) {
//扩大窗口
char cRight = s.charAt(right);
hashMap.put(cRight, hashMap.getOrDefault(cRight, 0) + 1);//记录c的数量
right++;
// System.out.println("left = " + left + " right = " + right);
//缩小窗口
while (/*满足条件*/hashMap.get(cRight) > 1) {
char cLeft = s.charAt(left);
hashMap.put(cLeft,hashMap.get(cLeft) - 1);
left++;
}
res = Math.max(res, right - left);
}
return res;
}
}
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案。
示例 1:输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
static class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> hashMap = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (hashMap.containsKey(target - nums[i])){
return new int[]{hashMap.get(target - nums[i]),i};
}
hashMap.put(nums[i],i);
}
return new int[]{};
}
}
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。字母异位词 是由重新排列源单词的所有字母得到的一个新单词。
示例 1:输入: strs = [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”]输出: [[“bat”],[“nat”,“tan”],[“ate”,“eat”,“tea”]]
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
//新建map
Map<String,List<String>> hashmap = new HashMap<>();
for (String str :
strs) {
//获取key
char[] chars = str.toCharArray();
Arrays.sort(chars);
String key = new String(chars);
//添加到list
List<String> list = hashmap.getOrDefault(key, new ArrayList<>());
list.add(str);
//添加到map
hashmap.put(key,list);
}
return new ArrayList<>(hashmap.values());
}
}
class Solution {
public int maxArea(int[] height) {
int left = 0,right = height.length - 1;
int res = 0;
while (left< right){
int area = (right - left) * Math.min(height[left],height[right]);
res = Math.max(res,area);
if (height[left] < height[right]){//最大面积取决于短板,移动短板
left ++;
}else {
right --;
}
}
return res;
}
}