简单记录CodeTop
1. 无重复字符的最长子串 CodeTop1
题目描述:给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
思路:
双指针 + HashMap存储当前字符串的下标 通过遍历字符串来改变左指针的位置 记录最大长度
public int lengthOfLongestSubstring(String str) {
//字符与符合字符的最大索引
HashMap<Character, Integer> map = new HashMap<>();
int left = 0;
int max = 0;
for (int i = 0; i < str.toCharArray().length; i++) {
//如果map中存在当前字符串
char cur = str.charAt(i);
if (map.containsKey(cur)) {
left = Math.max(map.get(cur) + 1, left);
}
map.put(cur, i);
max = Math.max(max, i - left + 1);
}
return max;
}
易错点:
通过 left = Math.max(map.get(cur) + 1, left);
需要保证left始终处于正确的位置 如abba时 当遍历到第二个a时 如果不进行比较而直接取 map.get(cur) + 1 则left则变成了1 而不是正确的2
2. 买卖股票的最佳时机 CodeTop17
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
思路:
双指针 small始终记录这个当前日期之前的最小股票 遍历数组 用max来维护做多获利金钱
public int maxProfit(int[] prices) {
int max = 0;
int small = prices[0];
for (int i = 1; i < prices.length; i++) {
if (prices[i] > small) {
max = Math.max(prices[i] - small, max);
} else {
small = prices[i];
}
}
return max;
}
3. 接雨水 CodeTop29
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
方法一
思路:
遍历数组 分别找到当前列左边和右边最高的 然后取较低的减去当前列的高度 就是当前列能存的水
public int trap(int[] height) {
int sum = 0;
for (int i = 0; i < height.length; i++) {
int left = 0;
int right = 0;
for (int j = 0; j < height.length; j++) {
if (height[j] > height[i]) {
if (j < i) {
left = Math.max(left, height[j] - height[i]);
} else {
right = Math.max(right, height[j] - height[i]);
}
}
}
sum += Math.max(Math.min(left, right), 0);
}
return sum;
}
}
缺点:
时间复杂度过高
方法二
思路:
用两个数组 分别维护当前位置左边最高的和右边最高的
ex:第i列 左边最高的 = max(i-1 列左边最高的, i-1 列的高度)
public int trap(int[] height) {
//记录某一列左边最高的
int[] maxLeft = new int[height.length];
//记录某一列右边最高的
int[] maxRight = new int[height.length];
for (int i = 1; i < height.length; i++) {
maxLeft[i] = Math.max(maxLeft[i - 1], height[i - 1]);
}
for (int i = height.length - 2; i >= 0; i--) {
maxRight[i] = Math.max(maxRight[i + 1], height[i + 1]);
}
int sum = 0;
for (int i = 1; i < height.length; i++) {
if (maxLeft[i] > height[i] && maxRight[i] > height[i]) {
sum += Math.min(maxLeft[i], maxRight[i]) - height[i];
}
}
return sum;
}
4. 三数之和 CodeTop6
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
思路:
利用两数之和的思路 遍历数组 将当前数字作为target 然后进行处理
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
//如果这个数字和上个数字重复 则直接跳过
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
//优化1:如果当前数字与最小的两个数字加起来都大于0 则直接返回结果
if (i < nums.length - 2 && nums[i] + nums[i + 1] + nums[i + 2] > 0) {
return ans;
}
//优化2:如果当前数字与最大的两个数加起来都小于0 则可以跳过当前数字 (仍有可能存在结果
if (nums[i] + nums[nums.length -1] + nums[nums.length -2] < 0) {
continue;
}
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
int sum = nums[left] + nums[right] + nums[i];
if (sum == 0) {
ans.add(Arrays.asList(nums[i], nums[left], nums[right]));
do{
left++;
//保证当前左指针不与上个相同
} while (left < right && nums[left] == nums[left - 1]);
do{
right--;
//保证当前右指针不与上个相同
} while (left < right && nums[right] == nums[right + 1]);
continue;
} else if (sum < 0) {
left++;
} else {
right--;
}
}
}
return ans;
}
5. 最长回文子串 CodeTop11
给你一个字符串 s,找到 s 中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
思路:
DP 思考状态转移方程
public String longestPalindrome(String s) {
int strLength = s.length();
//[i][j]存放从i到j的字符串是否为回文子串
boolean[][] bool = new boolean[strLength][strLength];
//单字符直接返回
if (s.length() < 2) {
return s;
}
//存放最大长度最小都为1
int max = 1;
//存放最大时的初始位置
int begin = 0;
//需要判断的字符串长度
for (int length = 2; length <= s.length(); length++) {
for (int i = 0; i < strLength; i++) {
//i为左index j为右index
int j = i + length -1;
if (j >= s.length()){
break;
}
if (s.charAt(i) == s.charAt(j)) {
//如果i和j之间无字符串或只有一个字符串 则为回文子串
if (j - i <= 2) {
bool[i][j] = true;
} else {
bool[i][j] = bool[i + 1][j - 1];
}
}
if (bool[i][j] & length > max) {
max = length;
begin = i;
}
}
}
return s.substring(begin, begin + max);
}
6. 岛屿数量 codeTop14
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:grid = [
[“1”,“1”,“1”,“1”,“0”],
[“1”,“1”,“0”,“1”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“0”,“0”,“0”]
]
输出:1
思路:
DFS
public int numIslands(char[][] grid) {
int num = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == '1') {
dfs(grid, i, j);
num++;
}
}
}
return num;
}
public void dfs(char[][] grid, int x, int y) {
if (x < 0 || y < 0 || x >= grid.length || y > grid[0].length || grid[x][y] != '1') {
return;
}
grid[x][y] = '2';
dfs(grid, x - 1, y);
dfs(grid, x + 1, y);
dfs(grid, x, y - 1);
dfs(grid, x, y + 1);
}
DFS框架:
//树的遍历
void traverse(TreeNode root) {
// 判断 base case
if (root == null) {
return;
}
// 访问两个相邻结点:左子结点、右子结点
traverse(root.left);
traverse(root.right);
}
//网格的遍历
void dfs(int[][] grid, int r, int c) {
// 判断 base case
// 如果坐标 (r, c) 超出了网格范围,直接返回
if (!inArea(grid, r, c)) {
return;
}
// 访问上、下、左、右四个相邻结点
dfs(grid, r - 1, c);
dfs(grid, r + 1, c);
dfs(grid, r, c - 1);
dfs(grid, r, c + 1);
}
// 判断坐标 (r, c) 是否在网格中
boolean inArea(int[][] grid, int r, int c) {
return 0 <= r && r < grid.length
&& 0 <= c && c < grid[0].length;
}
7. 有效括号 codeTop15
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
思路:
利用栈先进后出的规则
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(' || c == '[' || c == '{') {
stack.push(c);
} else {
if (stack.isEmpty()) {
return false;
}
if (c == ')' && stack.pop() != '(') {
return false;
}
if (c == ']' && stack.pop() != '[') {
return false;
}
if (c == '}' && stack.pop() != '{') {
return false;
}
}
}
return stack.isEmpty();
}
8. 全排列 codeTop19
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
思路:
回溯算法框架
// a:存放结果集合
// b:当前集合
// C:题目元素
void backtracking(List<List> a,List b,int[] cs){
if(b 符合 题目要求){
a.add(new ArrayList(b));
return;
}
for(c in cs){
if(c 满足 条件) {
b.add(c);
backtracking(a, b, c);
//回溯
b.remove(b.size() - 1);
}
}
}
//题解
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> ans = new ArrayList<>();
List<Integer> list = new ArrayList<>();
backtracking(ans, nums, list);
return ans;
}
public void backtracking(List<List<Integer>> ans, int[] nums, List<Integer> r) {
if (r.size() == nums.length) {
ans.add(new ArrayList<>(r));
return;
}
for (int i = 0; i < nums.length; i++) {
if (!r.contains(nums[i])) {
r.add(nums[i]);
backtracking(ans, nums, r);
r.remove(r.size() - 1);
}
}
}