十个算法题

自己挑的十个看起来高频或重要的算法题,仅供个人学习使用
题目和答案来自力扣题库

目录

121. 买卖股票的最佳时机

206. 反转链表

92. 反转链表 II

145. 二叉树的后序遍历

695. 岛屿的最大面积

98. 验证二叉搜索树

77. 组合

面试题 16.01. 交换数字

198. 打家劫舍


121. 买卖股票的最佳时机

计算最大利润,后的股价-当天的股价,或者立刻卖出

思路:贪心

class Solution {
    public int maxProfit(int[] prices) {
        int max = 0;
        int pre = prices[0];
        for(int cur : prices){
            if((cur - pre) > 0){
                max = Math.max(cur-pre, max);
            }
            else{
                pre = cur;
            }
        }
        return max;
    }
}

 

206. 反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

方法一:迭代

class Solution {
    public ListNode reverseList(ListNode head) {

        ListNode node = null;

        while(head != null){
            ListNode tmp = head.next;
            head.next = node;
            node = head;
            head = tmp;
        }
        return node;
    }
}

方法二:递归

class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }
        ListNode node = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return node;
    }
}

 

674. 最长连续递增序列

给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。

方法一:贪心

class Solution {
    public int findLengthOfLCIS(int[] nums) {
        int ans = 0;
        int n = nums.length;
        int start = 0;
        for(int i = 0; i < n; i++){
            if( i>0 && nums[i-1] >= nums[i] ){
                start = i;  //更新开始值
            }
            ans = Math.max(ans, i - start + 1);
        }
        return ans;
    }
}

方法二:动态规划(原题解

  1. 状态定义dp[i]:表示必须以nums[i]结尾的连续递增序列长度
  2. 状态转移:dp[i] = nums[i] > nums[i-1] ? dp[i-1] + 1 : 1;
  3. ans = max { dp[i] }
class Solution {
    public int findLengthOfLCIS(int[] nums) {
        int pre = 1; // pre表示dp[i-1]: 必须以i-1位置结尾的递增子数组长度
        int ans = pre;
        for (int i = 1; i < nums.length; i++) {
            int cur = nums[i] > nums[i-1] ? pre + 1 : 1; //更新当前值
            ans = Math.max(ans, cur);
            pre = cur;
        }
        return ans;
    }
}

 

92. 反转链表 II

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

方法一:截取中间的子链表,翻转再连接。

方法二:头插法,遍历一次

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        
        ListNode dummyNode = new ListNode(-1,head);

        // 找到前驱结点
        ListNode pre = dummyNode;
        for(int i = 0; i < left-1; i++) pre = pre.next;

        // 从前驱结点后一个开始
        ListNode cur = pre.next;
        ListNode tmp;
        for(int i = 0; i < right-left; i++){
            tmp = cur.next;
            cur.next = tmp.next;
            tmp.next = pre.next;
            pre.next = tmp;
        }
        return dummyNode.next;
    }
}

 

145. 二叉树的后序遍历

方法一:

一定要注意一下条件
先处理左孩子,再处理右孩子,最后处理自己

public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> res = new ArrayList<Integer>();
    if(root == null){
        return res;
    }
    Deque<TreeNode> stack = new LinkedList<TreeNode>();
    stack.push(root);
    TreeNode pre = root;
    while(!stack.isEmpty()){
        TreeNode cur = stack.peek();
        if(cur.left!= null && pre != cur.left && pre != cur.right){
            stack.push(cur.left);
        }else if(cur.right != null && pre != cur.right){
            stack.push(cur.right);
        }else{
            res.add(cur.val);
            stack.pop();
            pre = cur;
        }
    }
    return res;
}

方法二:

public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> res = new ArrayList<>();
    Deque<TreeNode> stack = new linkedList<>();
​
    while(root != null || !stack.isEmpty()){
        while(root != null){
            res.add(root.val); //处理节点
            stack.push(root);
            root = root.right;  //先把右边界入栈
        }
​
        TreeNode cur = stack.pop();
        root = cur.left;
    }
​
    Collections.reverse(res);   //反转数组
    return res;
}

 

695. 岛屿的最大面积

给定一个由 0 和 1 组成的二维矩阵,求岛屿的最大面积。

方法一:递归,深度优先

class Solution {
    int[] x0={1,-1,0,0};
    int[] y0={0,0,1,-1};
​
    public int maxAreaOfIsland(int[][] grid) {
        int area = 0;
        int m = grid.length;
        int n = grid[0].length;
        for(int i = 0; i < m; i++){
            for(int j =0; j <n; j++){
                if(grid[i][j] == 1){ //这个判断可以不要
                    area = Math.max(DFS(grid, i,j), area);
                }
            }
        }
        return area;
    }
​
    public int DFS(int[][] grid, int x, int y){
        if(x < 0 || x == grid.length || y < 0 || y == grid[0].length || grid[x][y] == 0){
            return 0;
        }
        grid[x][y] = 0;
        int ans = 1;
        for(int i = 0; i< 4; i++){
            ans +=DFS(grid, x+x0[i],y+y0[i]);   //这个面积累加就跟巧妙
        }
        return ans;
    }
}

方法二:迭代(栈),深度优先

因为每一个顶点有x,y两个信息量,所以用两个栈分别保存x坐标和y坐标

可以类比树的深度优先,左神的先序遍历,先右孩子再左孩子,弹出再右孩子左孩子

这里,相当于一个顶点有四个孩子,弹出将其孩子添加到栈中

    public int DFS(int[][] grid, int x, int y){
        int ans = 0;
​
        Deque<Integer> stackX = new LinkedList<>();
        Deque<Integer> stackY = new LinkedList<>();
        stackX.push(x);
        stackY.push(y);
​
        while (!stackX.isEmpty()){
            int cur_x = stackX.pop();
            int cur_y = stackY.pop();
            if (cur_x < 0 || cur_y < 0 || cur_x >= grid.length || cur_y >= grid[0].length || grid[cur_x][cur_y] != 1) {
                continue;
            }
            grid[cur_x][cur_y] = 0;
            ans++;
            for (int i = 0; i < 4; i++) {
                int dx = cur_x + x0[i];
                int dy = cur_y + y0[i];
                stackX.push(dx);
                stackY.push(dy);
            }
        }
        return ans;
    }

方法三:广度优先搜索

使用队列,出队添加所有孩子

98. 验证二叉搜索树

 给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

要注意的是测试用例的边界,精度都要大于INT才可测试通过

官方递归:

class Solution {
    public boolean isValidBST(TreeNode root) {
        return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }

    public boolean isValidBST(TreeNode node, long lower, long upper) {
        if (node == null) {
            return true;
        }
        if (node.val <= lower || node.val >= upper) {
            return false;
        }
        return isValidBST(node.left, lower, node.val) && isValidBST(node.right, node.val, upper);
    }
}
77. 组合

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

回溯
参考题解

class Solution {
	List<List<Integer>> res = new ArrayList<>();
	List<Integer> subset = new ArrayList<>();
    public List<List<Integer>> combine(int n, int k) {
		dfs(1,n,k);
		return res;
    }
	public void dfs(int start, int n, int k){
		if(subset.size() == k){
			res.add(new ArrayList<>(subset));
			return;
		}
		for (int i = start; i <= n ; i++) {
			subset.add(i);
			dfs(i+1,n,k);
			subset.remove(subset.size()-1);
		}
		return;
	}
}

 剪枝优化

private void dfs(int begin, int n, int k, Deque<Integer> path, List<List<Integer>> res) {
    if (k == 0) {
        res.add(new ArrayList<>(path));
        return;
    }

    // 基础版本的递归终止条件:if (begin == n + 1) {
    if (begin > n - k + 1) {
        return;
    }
    // 不选当前考虑的数 begin,直接递归到下一层
    dfs(begin + 1, n, k, path, res);

    // 不选当前考虑的数 begin,递归到下一层的时候 k - 1,这里 k 表示还需要选多少个数
    path.addLast(begin);
    dfs(begin + 1, n, k - 1, path, res);
    // 深度优先遍历有回头的过程,因此需要撤销选择
    path.removeLast();
}

 

面试题 16.01. 交换数字

编写一个函数,不用临时变量,直接交换numbers = [a, b]ab的值。

思路:^

相同的数异或为0,任何数与0异或得它本身,满足交换律和结合律

tmp = a ^ b,这里tmp表示a和b之间的差异,ab任何与tmp进行异或都可以将另一个数还原

那么,只需要tmp和a,b中的一个,就可以还原另一个数了

这样就只需两个变量保存了

// a = a ^ b  此时a为tmp
// b = a ^ b  此时b = tmp ^ b = a
// a = a ^ b  此时a = tmp ^ a = b

 

198. 打家劫舍

如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

 动态规划

方法一:

class Solution {
    public int rob(int[] nums) {
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        int max = nums[0];
        for(int i = 1; i < nums.length; i++ ){
            dp[i] = i!= 1 ? Math.max(dp[i-1], dp[i-2] + nums[i]) : Math.max(nums[0], nums[1]) ;
            max = Math.max(max, dp[i]);
        }
        return max;
    }
}

方法二:

class Solution {
    public int rob(int[] nums) {
        int pre = 0, cur = 0, tmp;
        for(int num : nums) {
            tmp = cur;
            cur = Math.max(pre + num, cur);
            pre = tmp;
        }
        return cur;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值