CodeTop 刷题记录

1. 无重复字符的最长子串 CodeTop1

LeetCode:无重复字符串的最长子串长度

题目描述:给定一个字符串 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

LeetCode:买卖股票的最佳时机

给定一个数组 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

LeetCode: 接雨水

给定 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

LeetCode: 三数之和

给你一个整数数组 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

LeetCode:最长回文子串

给你一个字符串 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

LeetCode岛屿数量

给你一个由 ‘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

LeetCode有效括号

给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 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

LeetCode全排列

给定一个不含重复数字的数组 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);
            }
        }
    }
  • 23
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值