力扣学习day4

1.学习目标

1.争取在2021年2月底刷完力扣10%题目。
2.从零开始学习C,C++,python。
3.用多种方法写出解题思路,以及理解代码。


2.意外收获

看到一位前辈总结的一些资料,感觉很有帮助,所以分享给大家。
网址地址:https://github.com/youngyangyang04/leetcode-master

3.学习内容:

3.1 leetcode18

18. 四数之和

(1)题目

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:

答案中不可以包含重复的四元组。

(2)思考

方法还是排序+双指针,以后无论多少之数之和都可以用这个方法,两数之和的话哈希法最快,但双指针也是可行的。

首先排序,然后确定i,j的位置,在i,j的右端开始遍历。遍历思路还是一个L,一个R分别指向max(i,j)+1,和最右端,再往根据target-sum的差值往中心取值。因为(i,j)的遍历时间复杂度为O(n^2) ,而(L,R)的遍历时间复杂度为O(n),所以总体的时间复杂度就为O(n^3)。

往深处思考,这类题目都是相同的算法,区别在于对基本值的遍历,假设是n数之和,则外轮有n-2次循环,把除确认(L,R)的所有可能都计算一遍。虽然我觉得可能还有更优秀的算法,但那需要更严谨的数学思考,但对于现阶段的我来说就算了。

3.2 leetcode19

19. 删除链表的倒数第 N 个结点

(1)题目

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

进阶:你能尝试使用一趟扫描实现吗?

(2)思考

换知识点了,这是对链表操作的考察。还是使用双指针吧,设置两个指针first和second,其中first=head,second->next=head,为了方便返回头节点,存储下当前的second。接着使用first遍历n次,second也随着遍历,当first指向第n个节点的时候,second指向n-1个节点,这时只要second->next=second->next->next即可删除,然后再把first节点free掉,返回之前存储的头节点即可。

第一次做的时候看错题目了,以为是删除顺序第n个节点,结果没注意到是倒数第n个。不过还是用双指针法,但是对初始条件的first和second做处理,first指向头节点,second指向first后的第n个节点,如果为NULL,则直接返回错误。然后两个指针一起遍历移动,直到second->next=NULL,则删除first这个节点。

但是要注意的是,不要弄错了first和second的相对位置,否则容易删错位置。

(2/25订正)

此外,这道题我看到一个大佬写的牛逼递归算法,当时还想了下可行性。然后真的是牛逼。
在这里插入图片描述

(3)递归算法代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    int cur=0;
    ListNode* removeNthFromEnd(ListNode* head, int n) {
       if(!head) return NULL;
       head->next = removeNthFromEnd(head->next,n);
       cur++;
       if(n==cur) return head->next;
       return head;
    }
};

3.3 leetcode 20

20. 有效的括号

(1)题目

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。

(2)思考

CSP和面试常考题目,方法就是使用栈,对于C语言选手来说,只能写个数组,然后自己编写下入栈,出栈操作。假设检测字符为(或{则入栈,遇到),}则出栈,如果出栈时判断不匹配,则无效字符串。假设,字符串已经为空,但是检测栈中元素不为0,则字符串无效。

3.4 leetcode 21

21. 合并两个有序链表

(1)题目

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

(2)思考

通常作为选择题来进行出题,考察时间复杂度和空间复杂度。我的思路也很简单,因为本身就是升序链表,因此只需要依次遍历即可,每次遍历小的则加入到新的链表当中,然后指针后移,直到链表为空。这种简单算法的时间复杂度和空间复杂度均为O(m+n),m,n分别是两个链表的长度。

3.5 leetcode 22

22. 括号生成

(1)题目

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

(2)思考

感觉思路还是很清晰,但是代码动手起来有点不知所措,考点应该时回溯法。根据我的经验,C语言用递归很容易奔溃,只要层数大起来,就会栈溢出。

首先输入只有"(“和”)",我们按从左到右的顺序输入,因为只有两个选择,所以脑海里可以很容易的想到二叉树的图形。

那么我们简单以二叉树为例,左子树表示输入左括号,右子树输入右括号。且制定一个规则来结束不规则的括号组合,当右括号数量大于左括号时停止进行剪枝;另一种情况就是当左括号数量大于n时停止剪枝。

回溯法也是重点考察的地方,还要注意和递归的区别之处,我感觉这也是我之后学习的地方之一。

这是我看到的一个最容易懂的代码,很有借鉴意义。

class Solution(object):
    def generateParenthesis(self, n):
        """
        :type n: int
        :rtype: List[str]
        """
        res = []
        self.dfs(res, n, n, '')
        return res
        
    def dfs(self, res, left, right, path):
        if left == 0 and right == 0:
            res.append(path)
            return
        if left > 0:
            self.dfs(res, left - 1, right, path + '(')
        if left < right:
            self.dfs(res, left, right - 1, path + ')')

3.6 leetcode 23

23. 合并K个升序链表

(1)题目

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

(2)官方解答

照搬下官方的思路,因为这道题我也曾在面试的时候被问及过,感觉十分有纪念价值。

在解决「合并K个排序链表」这个问题之前,我们先来看一个更简单的问题:如何合并两个有序链表?假设链表 aa 和 bb 的长度都是 nn,如何在 O(n)O(n) 的时间代价以及 O(1)O(1) 的空间代价完成合并? 这个问题在面试中常常出现,为了达到空间代价是 O(1)O(1),我们的宗旨是「原地调整链表元素的 next 指针完成合并」。

先我们需要一个变量 head 来保存合并之后链表的头部,你可以把 head 设置为一个虚拟的头(也就是 head 的 val 属性不保存任何值),这是为了方便代码的书写,在整个链表合并完之后,返回它的下一位置即可。

我们需要一个指针 tail 来记录下一个插入位置的前一个位置,以及两个指针 aPtr 和 bPtr 来记录 aa 和 bb 未合并部分的第一位。注意这里的描述,tail 不是下一个插入的位置,aPtr 和 bPtr 所指向的元素处于「待合并」的状态,也就是说它们还没有合并入最终的链表。 当然你也可以给他们赋予其他的定义,但是定义不同实现就会不同。

当 aPtr 和 bPtr 都不为空的时候,取 val 熟悉较小的合并;如果 aPtr 为空,则把整个 bPtr 以及后面的元素全部合并;bPtr 为空时同理。

在合并的时候,应该先调整 tail 的 next 属性,再后移 tail 和 *Ptr(aPtr 或者 bPtr)。那么这里 tail 和 *Ptr 是否存在先后顺序呢?它们谁先动谁后动都是一样的,不会改变任何元素的 next 指针。

4.感想

之前做题没有方向感觉收效不大,今天找到大佬的学习总结,感觉可以借鉴下学习顺序。另外,因为最近还要看相关深度学习和面试技巧,打算之后的力扣学习以专题为主。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

此人受打击,决定去力扣历练

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值