目录
数据结构与算法
面试注意点
练习
链表
基本技能
常见题型
83. 删除排序链表中的重复元素:remove-duplicates-from-sorted-list
82. 删除排序链表中的重复元素 II remove-duplicates-from-sorted-list-ii
206. 反转链表:reverse-linked-list
92. 反转链表 II:reverse-linked-list-ii
21. 合并两个有序链表merge-two-sorted-lists
86. 分隔链表:partition-list
148. 排序链表sort-list
143. 重排链表reorder-list
141. 环形链表linked-list-cycle
142 环形链表 Ⅱ linked-list-cycle-ii
234. 回文链表palindrome-linked-list
138. 复制带随机指针的链表copy-list-with-random-pointer
总结
练习
1. 两数之和
2. 两数相加
26. 删除排序数组中的重复项
160 相交链表(easy)
19 删除链表的倒数第N个结点(medium)
203 移除链表元素(easy)
328 奇偶链表
430 扁平化多级双向链表
61 旋转链表(medium)
算法快速入门
数据结构是一种数据的表现形式,如链表、二叉树、栈、队列等都是内存中一段数据表现的形式。 算法是一种通用的解决问题的模板或者思路,大部分数据结构都有一套通用的算法模板,所以掌握这些通用的算法模板即可解决各种算法问题。
后面会分专题讲解各种数据结构、基本的算法模板、和一些高级算法模板,每一个专题都有一些经典练习题,完成所有练习的题后,你对数据结构和算法会有新的收获和体会。
先介绍两个算法题,试试感觉~
示例 1
strStr
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从 0 开始)。如果不存在,则返回 -1。
思路:核心点遍历给定字符串字符,判断以当前字符开头字符串是否等于目标字符串
需要注意点
循环时,i 不需要到 len-1
如果找到目标字符串,len(needle)==j
示例 2
subsets
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
思路:这是一个典型的应用回溯法的题目,简单来说就是穷尽所有可能性,算法模板如下
通过不停的选择,撤销选择,来穷尽所有可能性,最后将满足条件的结果返回
说明:后面会深入讲解几个典型的回溯算法问题,如果当前不太了解可以暂时先跳过
我们大多数时候,刷算法题可能都是为了准备面试,所以面试的时候需要注意一些点
快速定位到题目的知识点,找到知识点的通用模板,可能需要根据题目特殊情况做特殊处理。
先去朝一个解决问题的方向!先抛出可行解,而不是最优解!先解决,再优化!
代码的风格要统一,熟悉各类语言的代码规范。
命名尽量简洁明了,尽量不用数字命名如:i1、node1、a1、b2
常见错误总结
访问下标时,不能访问越界
空值 nil 问题 run time error
strStr
subsets
链表相关的核心点
null/nil 异常处理
dummy node 哑巴节点
快慢指针
插入一个节点到排序链表
从一个链表中移除一个节点
翻转链表
合并两个链表
找到链表的中间节点
83. 删除排序链表中的重复元素:模拟题
,直接遍历链表,遇到重复值的节点删除即可。
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
83. 删除排序链表中的重复元素
#直接法:
这是一个简单的问题,仅测试你操作列表的结点指针的能力。由于输入的列表已排序,
# 因此我们可以通过将结点的值与它之后的结点进行比较来确定它是否为重复结点。
# 如果它是重复的,我们更改当前结点的 next 指针,
# 以便它跳过下一个结点并直接指向下一个结点之后的结点。
解法https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/solution/hua-jie-suan-fa-83-shan-chu-pai-xu-lian-biao-zhong/
图解https://pic.leetcode-cn.com/c61a88b9fe012a9b85b842f4a12a5310c96b462ea4801e6227fc6a04aa140351-frame_00001.png
# Python3
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
cur=head
while cur and cur.next:
if cur.val==cur.next.val:
cur.next=cur.next.next
else:
cur=cur.next
return head
# 输入 输出
# [1,2,2] [1,2]
# [1,1,1] [1]
# 复杂度分析
# 时间复杂度:O(n),因为列表中的每个结点都检查一次以确定它是否重复,
# 所以总运行时间为 O(n),其中 n 是列表中的结点数。
# 空间复杂度:O(1),没有使用额外的空间。
# 此题需要返回一个没有重复元素的新链表,因为没有链表没有下标,
# 如果使用「双指针」(双引用),后面覆盖前面,可行。
# 但返回新链表,实现起来比较复杂。
# 此题可借助链表的特性「指针」(Pointer)来实现。
# 如果当前节点的值等于下一个节点的值,指向下下个节点(跳过下一个节点),
# 引用 head 并后移一位。
82. 删除排序链表中的重复元素 II:模拟题
,遍历链表,若head的节点值与head的next节点值不相等,则pre指向head,也就是不重复节点;若相等,我们需要找到重复值子链表的最后一个节点,然后令pre指向head->next,同时head移动到下一个节点。
思路:链表头结点可能被删除,所以用 dummy node 辅助删除
给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现的数字。
示例 1:
输入: 1->2->3->3->4->4->5
输出: 1->2->5
示例 2:
输入: 1->1->1->2->3
输出: 2->3
解法二
https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/solution/san-chong-jie-fa-duo-tu-zhan-shi-82-shan-chu-pai-x/
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def deleteDuplicates(self, head):
if not (head and head.next):
return head
dummy = ListNode(-1)
dummy.next = head
a = dummy
b = head
while b and b.next:
# 初始化的时a指向的是哑结点,所以比较逻辑应该是a的下一个节点和b的下一个节点
if a.next.val!=b.next.val:
a = a.next
b = b.next
else:
# 如果a、b指向的节点值相等,就不断移动b,直到a、b指向的值不相等
while b and b.next and a.next.val==b.next.val:
b = b.next
a.next = b.next
b = b.next
return dummy.next
206. 反转链表:双指针法
,指针pre用来表示前驱节点,指针cur用来遍历链表,每次循环改变将pre->cur
的方向改变为pre<-cur
,直到遍历结束。
反转一个单链表。
思路:用一个 prev 节点保存向前指针,temp 保存向后的临时指针
https://leetcode-cn.com/problems/reverse-linked-list/solution/dong-hua-yan-shi-206-fan-zhuan-lian-biao-by-user74/
https://mp.weixin.qq.com/s?__biz=MzAxODQxMDM0Mw==&mid=2247484467&idx=1&sn=beb3ae89993b812eeaa6bbdeda63c494&chksm=9bd7fa3baca0732dc3f9ae9202ecaf5c925b4048514eeca6ac81bc340930a82fc62bb67681fa&scene=21#wechat_redirect
双指针迭代
用 O(1) 空间复杂度来实现这道题。