leetCode ---50

本文涵盖了数据结构与算法的多个经典问题,包括二叉树的展开为链表、买卖股票的最佳时机、最大路径和以及最长连续序列长度的计算。通过实例解析了如何运用先序遍历、动态规划和哈希表等技巧解决这些问题,旨在提升算法思维和编程能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

114-二叉树展开为链表

给你二叉树的根结点 root ,请你将它展开为一个单链表:
展开后的单链表应该同样使用TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
展开后的单链表应该与二叉树 先序遍历 顺序相同。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public void flatten(TreeNode root) {
        if(root==null) return;
        Deque<TreeNode> stack = new LinkedList<>();
        stack.push(root);
        //先序遍历同时链接
        TreeNode pre = null;
        while(!stack.isEmpty()){
            TreeNode cur = stack.pop();
            if(pre!=null){
                pre.left = null;
                pre.right = cur;
            }
            //当前节点的左子树右子树入栈
            TreeNode left = cur.left, right = cur.right;
            if(right!=null) stack.push(right);
            if(left!=null) stack.push(left);
            pre = cur;
        }
    }
}

121-买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1:

输入:[7,1,5,3,6,4] 输出:5 解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 =
6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票

价格最低点买入,最高点抛出
只需标记最低价格,和最大利润,依次比较即可

class Solution {
    public int maxProfit(int[] prices) {
        if(prices.length==0) return 0;
        //价格最低点
        int minPrice = Integer.MAX_VALUE;
        int maxProfit = 0;
        for(int i=0;i<prices.length;i++){
            //当前价格小于最低价时,更新最小值
            if(prices[i]<minPrice){
                minPrice = prices[i];
            }else{
            //大于最小值则更新利润
                maxProfit = Math.max(maxProfit,prices[i]-minPrice);
            }
        }
        return maxProfit;
    }
}

124-最大路径和

路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径
至少包含一个 节点,且不一定经过根节点。

路径和 是路径中各节点值的总和。

给你一个二叉树的根节点 root ,返回其 最大路径和

在这里插入图片描述

输入:root = [1,2,3]
输出:6
解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    //要注意时最大路径和,一个节点的最大路径和=当前节点+左子树路径和+右子树路径和
    //不要搞混 贡献值和路径和的关系
    int maxSum = Integer.MIN_VALUE;
    public int maxPathSum(TreeNode root) {
        maxGain(root);
        return maxSum;
    }
    private int maxGain(TreeNode node){
        if(node==null) return 0;
        // 递归计算左右子节点的最大贡献值
        // 只有在最大贡献值大于 0 时,才会选取对应子节点
        int leftGain = Math.max(maxGain(node.left),0);
        int rightGain = Math.max(maxGain(node.right),0);
        int priceNewpath = node.val+leftGain+rightGain;
        //更新最大路径和
        maxSum = Math.max(maxSum,priceNewpath);
        
        //返回该节点最大贡献值
        return node.val + Math.max(leftGain,rightGain);
    }
}

128-最长序列长度

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

进阶:你可以设计并实现时间复杂度为 O(n) 的解决方案吗?

示例 1:

输入:nums = [100,4,200,1,3,2] 输出:4 解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。

class Solution {
    //遍历数组,然后查看数组中是否存在x-1,存在则跳过,不存在则遍历x+1,x+2,直到查找完毕
    //为了方便,元素的查找使用哈希表存储数组元素
    //先用set保存原数组,达到去重的效果
    public int longestConsecutive(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for(int num:nums){
            set.add(num);
        }
        //记录长度
        int longestStreak = 0;
        for(int num:set){
            if(set.contains(num-1)){
                continue;
            }else{
                int currentNum = num;
                int currentStreak = 1;
                //查找x+1....x+n
                while(set.contains(currentNum+1)){
                    currentNum += 1;
                    currentStreak += 1;
                }
                //记录最长序列长度
                longestStreak = Math.max(longestStreak,currentStreak);
            }
        }
        return longestStreak;
    }
}

136-只出现一次的数

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,1] 输出: 1

class Solution {
    public int singleNumber(int[] nums) {
        //题目中指明除了出现一次的数,其他数都出现两次
        //因此可以使用异或 a^a = 0,a^a^b = b
        int ans = 0;
        for(int num:nums){
            ans ^=num;
        }
        return ans;
    }
}

139-单词拆分

给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
拆分时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。

示例 1:

输入: s = “leetcode”, wordDict = [“leet”, “code”] 输出: true 解释: 返回 true
因为 “leetcode” 可以被拆分成 “leet code”。

示例 2:

输入: s = “applepenapple”, wordDict = [“apple”, “pen”] 输出: true 解释: 返回
true 因为 “applepenapple” 可以被拆分成 “apple pen apple”。
注意你可以重复使用字典中的单词。

link

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        Set<String> wordDictSet = new HashSet(wordDict);
        //依次遍历判断当前位置前的单词是否合法
        boolean[] dp = new boolean[s.length()+1];
        dp[0] = true;
        for(int i=1;i<=s.length();i++){
            //判断dp[i]是否合法,依次从第一个位置开始判断
            for(int j=0;j<i;j++){
                if(dp[j] && wordDictSet.contains(s.substring(j, i))){
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[s.length()];
    }
}

141-环形链表

判断链表是否存在环:(同剑指判断有环链表的入口

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) {
            return false;
        }
        ListNode slow = head;
        ListNode fast = head.next;
        while (slow != fast) {
            if (fast == null || fast.next == null) {
                return false;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        return true;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值