题目描述:给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
先添加右元素,再if(i!=0)先删除remove左元素
,ans=Math.max(ans, ans.size())(后一个ans是新ans)public int lengthOfLongestSubstring(String s) {
Set<Character> set = new HashSet<>(); // 哈希集合,记录每个字符是否出现过
int n = s.length();
int r = -1, ans = 0; // 右指针,初始值为 -1,for循环首先执行while从r+1开始添加
for (int i = 0; i < n; i++) {
if (i != 0) { // 左指针先remove,再不断移动右指针
set.remove(s.charAt(i - 1));
}
while (r < n && r + 1 < n && !set.contains(s.charAt(r + 1))) {
set.add(s.charAt(r + 1)); // 先r+1,再++(如果r+1满足,就让r变为r+1)
++r;
}
ans = Math.max(ans, set.size());
}
return ans;
}
题目描述:以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
public int[][] merge(int[][] intervals) {
if (intervals.length == 0) return new int[0][2];
Arrays.sort(intervals, new Comparator<int[]>() { // 直接Arrays.sort()就可以对数组进行修改
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] - o2[0]; // 谁在右边谁大:o2[0]大的顺序
}
});
List<int[]> ans = new ArrayList<>();
for (int i = 0; i < intervals.length; i++) {
int left = intervals[i][0], right = intervals[i][1];
if (ans.size() == 0 || ans.get(ans.size() - 1)[1] < left) { // 首一维数组or区间不交叉的数组
ans.add(intervals[i]);
} else {
ans.get(ans.size() - 1)[1] = Math.max(ans.get(ans.size() - 1)[1], right);
}
}
return ans.toArray(new int[ans.size()][2]); // List转数组
}
ans.add(new ArrayList<>(Arrays.asList(nums[i], nums[left], nums[right])));
来添加元素进ans
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans = new ArrayList<>();
if (nums == null || nums.length <= 2) return ans;
Arrays.sort(nums); // 排序nlogn
for (int i = 0; i < nums.length; i++) { // 时间复杂度n2
if (nums[i] > 0) break; // 第一个数大于0,后面两个数都大于0,且i后面肯定也>0,后面循环不成立
if (i > 0 && nums[i] == nums[i - 1]) continue; // 去重
int target = -nums[i];
int left = i + 1, right = nums.length - 1;
while (left < right) {
if (nums[left] + nums[right] == target) {
ans.add(new ArrayList<>(Arrays.asList(nums[i], nums[left], nums[right])));
left++;right--; // target一定,改变left肯定也要改变right,否则另一个数和上一次的一样了
while (left < right && nums[left] == nums[left - 1]) left++; // 去重:去掉和上一个left即left-1重复的
while (left < right && nums[right] == nums[right + 1]) right--; // 去重:去掉和上一个right即right+1重的
} else if (nums[left] + nums[right] < target) { // 整体小要变大,此时right已经到最右边了,只能加左边
left++;
} else {
right--;
}
}
}
return ans;
}
题目描述:
给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
示例 1:
输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
示例 2:
输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
rightMost = Math.max(rightMost, i + nums[i]);更新
;外层for循环i=0 - n-1,内层if(i<=rightMost)的时候进行判断>=nums.length-1以题目中的示例一
[2, 3, 1, 1, 4]
为例:
我们一开始在位置 00,可以跳跃的最大长度为 22,因此最远可以到达的位置被更新为 22;
我们遍历到位置 11,由于 1 \leq 21≤2,因此位置 11 可达。我们用 11 加上它可以跳跃的最大长度 33,将最远可以到达的位置更新为 44。由于 44 大于等于最后一个位置 44,因此我们直接返回 True。
public boolean canJump(int[] nums) {
int rightMost = 0;
for (int i = 0; i < nums.length; i++) {
if (i <= rightMost) { // 首元素满足0=0 // 遍历下标为i位置
rightMost = Math.max(rightMost, i + nums[i]); // rightMost为max(上一次最大,i+nums[i]),即i位置所能跑的最远距离
if (rightMost >= nums.length - 1) return true;
}
}
return false;
}
(lson && rson) || ((root.val == p.val || root.val == q.val) && (lson || rson)
】题目描述:
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
示例 1:
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。
示例 2:
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。
示例 3:
输入:root = [1,2], p = 1, q = 2
输出:1
return lson || rson || (root.val == p.val || root.val == q.val)
;最近公共祖先
以后,按定义被设置为 true ,即假定了这个子树中只有一个 pp 节点或 qq 节点,因此其他公共祖先不会再被判断为符合条件。由于所有结点的val都不相同,所以不会存在其他节点为True && 子树也为True
的情况public class 第236题二叉树的最近公共祖先 {
private static TreeNode ans;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
dfs(root, p, q);
return ans;
}
public static boolean dfs(TreeNode root, TreeNode p, TreeNode q) {
if (root == null) return false;
boolean lson = dfs(root.left, p, q);
boolean rson = dfs(root.right, p, q);
if ((lson && rson) || ((root.val == p.val || root.val == q.val) && (lson || rson))) { // 找到ans
ans = root;
}
return lson || rson || (root.val == p.val || root.val == q.val); // 返回条件
}
}
链接:Java实现字符串的全排列
题目描述:给定一个字符串s,返回其不重复的全排列
输入:“ABA”
输出:ABA、AAB、BAA
public class 全排列 {
public static List<String> fullArr(String s) {
List<String> list = new ArrayList<>(); // 使用一个list来存储全排列的结果
list.add("" + s.charAt(0)); // 初始化list数组,添加字符串的第一个元素 例:A
for (int i = 1; i < s.length(); i++) {
List<String> new_list = new ArrayList<>(); // 创建临时数组存储本次for循环生成的结果
char ch = s.charAt(i);
for (String str : list) { // 遍历当前list
new_list.add(str + ch); // 新字符插入到字符串的右面,并加入new_list 例:AB
new_list.add(ch + str); // 新字符插入到字符串的左面,并加入new_list 例:BA
for (int j = 1; j < str.length(); j++) { // 新字符插入到字符串的中间(当list中只有一个元素的时候length=1,for循环不满足<条件不会执行)
String str2 = str.substring(0, j) + ch + str.substring(j); // length=2的时候正好 左+ch+右
new_list.add(str2); // 新字符插入中间,并加入new_list
}
}
list = new_list; // 同步new_list给list,继续下一步的for循环
}
// 去重,建议用set
List<String> ans = new ArrayList<>();
for (String str : list) {
if (!ans.contains(str)) { // contains是On查找
ans.add(str);
}
}
return ans;
}
public static void main(String[] args) {
// String s = "ABCA";
String s = "ABA";
for (String str : fullArr(s)) {
System.out.println(str);
}
}
}