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”。
注意你可以重复使用字典中的单词。
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;
}
}