LeeCode热题100刷题记录

 持续更新中....坚持在期末的日子里每日两题。

一、哈希 

1.两数之和

(1)题目

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

(2)解答

我是真的菜哈哈,看到里面有句话 “ 有人相爱,有人夜里开车看海,有人leetcode第一题都做不出来。”

我真的是暴力解出来的,官方提供了一种使用哈希的解法让时间复杂度降下来:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> hashtable;
        for (int i = 0; i < nums.size(); ++i) {
            auto it = hashtable.find(target - nums[i]);
            if (it != hashtable.end()) {
                return {it->second, i};
            }
            hashtable[nums[i]] = i;
        }
        return {};
    }
};

二、动态规划

70.爬阶梯

(1)题目

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

(2)解答

这个就是斐波那锲数列,但是用递归的话超时了,所以就要用非递归的方法。

class Solution {
public:
    int climbStairs(int n) {
        if(n==1) return 1;
        if(n==2) return 2;
        int sum=0;
        int a1=1;
        int a2=2;
        for(int i=3;i<=n;i++){
            sum=a1+a2;
            a1=a2;
            a2=sum;
        }
        return sum;
    }
};

三、回溯

46.全排列问题

(1)题目

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

示例 2:

输入:nums = [0,1]
输出:[[0,1],[1,0]]

示例 3:

输入:nums = [1]
输出:[[1]]

(2)解答

就是很正常的回溯法,不过这个是需要用到递归的,然后要注意每次排列都要换回去,不然乱七八糟的。

class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> final_list;
        perm(nums,final_list,0,nums.size()-1);
        return final_list;
    }
    void perm(vector<int>& nums,vector<vector<int>>& final_nums,int l,int m){
        if(l==m){
             vector<int> list_try;
            for(int i=0;i<=m;i++){
                list_try.push_back(nums[i]);
            }
            final_nums.push_back(list_try);
        }
        else{
            for(int i=l;i<=m;i++){
                swap(nums[l],nums[i]);
                perm(nums,final_nums,l+1,m);
                swap(nums[l],nums[i]);
            }
        }

    }
};

四、链表

160.相交链表

(1)题目

(2)解答

这里用到了一歌方法来消除链表之间的长度不同:

假设有两个链表A和B,长度分别为L1L2。如果一个链表比另一个长,当两个链表的指针同时从各自的头部出发时,较长链表的指针会先到达末端。为了同步两个链表,使它们可以一起到达相交点,可以采用以下策略:

  • 指针pA开始时指向链表A的头部,指针pB指向链表B的头部。
  • pA遍历到链表A的末尾时,将pA重置到链表B的头部继续遍历;同样,当pB遍历到链表B的末尾时,将pB重置到链表A的头部继续遍历。
为什么这样可以消除长度差?

通过上述步骤,每个指针都将遍历长度为L1 + L2的路径。这样做的关键在于,当两个指针在各自链表的末尾“交换”起点后,它们会以相同的速度前进,并同时到达相交点(如果存在的话)。

  • 第一阶段:两个指针分别在自己的链表中前进。
  • 第二阶段:指针交换起点后,开始遍历对方的链表。

这种方法的精妙之处在于,当两个指针“交换”后,如果链表相交,那么因为交换起点,两个指针到达相交点的距离是相等的。即使两个链表不相交,指针也会同时到达各自链表的末尾(此时都是null),从而结束循环。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *pa=headA;
        ListNode *pb=headB;
        while (pA != pB) {
            // If reaching the end of one list, start from the beginning of the other
            pA = pA == NULL ? headB : pA->next;
            pB = pB == NULL ? headA : pB->next;
        }
        return headA0;
    }
};

五、二叉树

46.二叉树中序遍历

(1)题目

(2)解答

二叉树遍历用最简单的方法就是递归遍历。只要记住:

前序遍历根->左->右

中序遍历左->根->右

后序遍历左->右->根

那么递归的顺序一目了然。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> final_answer;
        if(root==NULL){
            return final_answer;
        }
        middleOrderTraversal(final_answer,root);
        return final_answer;

    }
    void middleOrderTraversal(vector<int>& v_list,TreeNode* root) {//传递记得加上引用个哈哈
        if(root==NULL){
            return;
        }
        middleOrderTraversal(v_list,root->left);
        v_list.push_back(root->val);
        middleOrderTraversal(v_list,root->right);
    }
};

只要换一下下面的代码的顺序就可以了。

然后看到评论区的题解,发现很有意思,就是前中后遍历的代码是一样的:

在树的深度优先遍历中(包括前序、中序、后序遍历),递归方法最为直观易懂,但考虑到效率,我们通常不推荐使用递归。

栈迭代方法虽然提高了效率,但其嵌套循环却非常烧脑,不易理解,容易造成 “一看就懂,一写就废” 的窘况。而且对于不同的遍历顺序(前序、中序、后序),循环结构差异很大,更增加了记忆负担。

因此,我在这里介绍一种 “颜色标记法” (瞎起的名字……),兼具栈迭代方法的高效,又像递归方法一样简洁易懂,更重要的是,这种方法对于前序、中序、后序遍历,能够写出完全一致的代码。

其核心思想如下:

使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。
如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。
如果遇到的节点为灰色,则将节点的值输出。

作者:henry
链接:https://leetcode.cn/problems/binary-tree-inorder-traversal/solutions/25220/yan-se-biao-ji-fa-yi-chong-tong-yong-qie-jian-ming/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        WHITE, GRAY = 0, 1
        res = []
        stack = [(WHITE, root)]
        while stack:
            color, node = stack.pop()
            if node is None: continue
            if color == WHITE:
                stack.append((WHITE, node.right))
                stack.append((GRAY, node))
                stack.append((WHITE, node.left))
            else:
                res.append(node.val)
        return res

五、贪心算法

121.买股票的最佳时机

(1)题目

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

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

示例 1:

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

示例 2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

(2)解答

就是说我又一次的忘记了命名不能够作为变量...我真傻。

#include <bits/stdc++.h>
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int min_price=pow(10,4);
        int profit=0;
        for(int i=0;i<prices.size();i++){
           profit=max(profit,prices[i]-min_price);
           min_price=min(min_price,prices[i]);
        }
        return profit;
    }
};

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值