1.接雨水
给定 n
个非负整数表示每个宽度为 1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
提示:
n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105
java
public static void main(String[] args) {
int[] nums = {0,1,0,2,1,0,1,3,2,1,2,1};
int trap = trap2(nums);
System.out.println(trap);
}
/**
* others:
* 思路:
* 使用双指针,左、右往中间逼近,找碗(的条件:左高中低右高,右≥左>中)
* eg.int[] nums = {0,2,1,3,1,2,1};
* 左<右,左指针动
* 左≥右,右指针动(碗的条件:左高中低右高,右≥左>中)
* ①从左往右看,成碗(0<1),左动,格子没下降(没办法装水),s不变,s=0
* ②从右往左看,成碗(2>1),右动,格子没下降(没办法装水),s不变,s=0
* ③从右往左看,成碗(2<=2),右动,格子下降,s=0+下降的高度=1
* ④从左往右看,成碗(2>1),左动,格子下降,s=1+下降的高度=2
* ⑤从右往左看,成碗(1<=1),右动,格子没下降(没办法装水),s不变,s=2
* ⑥从右往左看,成碗(1<=3),右动,左右指针相遇,结束
* max值的作用,判断格子是否下降(与指针所在值比较)
* @param height
* @return
*/
public static int trap2(int[] height) {
int ans = 0;
int left = 0, right = height.length - 1;
int leftMax = 0, rightMax = 0;
while (left < right) {
leftMax = Math.max(leftMax, height[left]);
rightMax = Math.max(rightMax, height[right]);
if (height[left] < height[right]) {
ans += leftMax - height[left];
++left;
} else {
ans += rightMax - height[right];
--right;
}
}
return ans;
}
/**
* my:
* 思路:
* 单向遍历判断,存储成碗的区间index,尾巴处(最后一个区间index)可能存在不满足成碗(右≥左>中)的特殊情况,左>右,逆序后调用一次方法本身可解决
* @param height
* @return
*/
public static int trap(int[] height) {
List<List<Integer>> indexList = new ArrayList<>();
for (int i = 0; i+1 < height.length; i++) {
if (height[i]>height[i+1]){
List<Integer> inner = new ArrayList<>();
inner.add(i);
for (int j = i + 1; j < height.length; j++) {
inner.add(j);
if (height[j] >= height[i])
break;
}
indexList.add(inner);
int jumpIndex = inner.size();
if (jumpIndex > 0)
i = i + jumpIndex - 2;
}
}
List<Integer> targetList = new ArrayList<>();
for (List<Integer> innerIndexList : indexList) {
if (height[innerIndexList.get(0)]>height[innerIndexList.get(innerIndexList.size()-1)]){
// 创建新数组
int[] reversedArray = new int[innerIndexList.size()];
// 逆序填充
for (int i = 0; i < innerIndexList.size(); i++) {
reversedArray[i] = height[innerIndexList.get(innerIndexList.size() - 1 - i)]; // 从后往前取
}
int trap = trap(reversedArray);
targetList.add(trap);
}else {
int innerHeight = height[innerIndexList.get(0)];
// 使用 IntStream.sum()(更高效)
int sum = innerIndexList
.stream()
.mapToInt(o -> innerHeight >= height[o] ? innerHeight - height[o] : 0)
.sum();
targetList.add(sum);
}
}
// 使用 IntStream.sum()(更高效)
int sum = targetList
.stream()
.mapToInt(Integer::intValue).sum();
return sum;
}
思路不一样
2.无重复字符的最长子串
给定一个字符串 s
,请你找出其中不含有重复字符的 最长 子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
提示:
0 <= s.length <= 5 * 104
s
由英文字母、数字、符号和空格组成
java
public static void main(String[] args) {
String s1 = "pwwkew";
String s2 = " ";
String s = "dvdf";
int lengthOfLongestSubstring = lengthOfLongestSubstring(s);
System.out.println(lengthOfLongestSubstring);
}
/**
* 思路:
* 滑动窗口
*
* 关键步骤:
* 1.右指针 right 扩展窗口:
* 遍历每个字符,尝试将其加入当前窗口。
* 2.处理重复字符:
* 如果 c[right] 已经在窗口中(cnt[c[right]] > 0),则移动左指针 left,并减少对应字符的计数,直到 c[right] 不再重复。
* 3.更新窗口长度:
* 计算当前窗口长度 right - left + 1,并更新最大值 ans。
* @param s
* @return
*/
public static int lengthOfLongestSubstring2(String s) {
int ans = 0; // 存储最长无重复子串的长度
int left = 0; // 滑动窗口的左边界
char[] c = s.toCharArray(); // 将字符串转为字符数组,方便遍历
int n = c.length; // 字符串长度
int[] cnt = new int[128]; // ASCII 字符计数数组(默认初始化为 0)
//cnt[128]:用于记录当前窗口中每个字符的出现次数(ASCII 字符范围 0-127)。
//left 和 right:定义滑动窗口的左右边界。
for (int right = 0; right < n; right++) {
// 如果当前字符 c[right] 已经存在于窗口中,则移动左边界
while (cnt[c[right]] > 0) {
cnt[c[left]]--; // 移除左边界字符的计数
left++; // 左边界右移
}
// 将当前字符加入窗口
cnt[c[right]]++;
// 更新最大长度
ans = Math.max(ans, right - left + 1);
}
return ans;
}
public static int lengthOfLongestSubstring(String s) {
String currentSubstring = "";
int longestLen = 0;
for (int i = 0; i < s.length(); i++) {
if (currentSubstring.contains(String.valueOf(s.charAt(i)))) {
if (currentSubstring.length()>longestLen){
longestLen = currentSubstring.length();
}
int indexOf = currentSubstring.indexOf(s.charAt(i));
if (indexOf+1 <= s.length()-1){
currentSubstring = currentSubstring.substring(indexOf + 1);
}else {
currentSubstring = "";
}
}
currentSubstring+=s.charAt(i);
}
if (currentSubstring.length()>longestLen){
longestLen = currentSubstring.length();
}
return longestLen;
}
思路一样