动态规划(Dynamic programming,简称DP)
动态规划算法的基本思想与分治法类似,也是将求解的问题分解为若干字问题,按顺序求解子阶段,前一子问题的解,为后一子问题提供了有用的信息。在求解任意子问题,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解决。
你在我的心上说来最情长
分治法是建基于多项分支递归的一种算法范式,字面意思”分而治之“,把一个复杂的问题分为两个或者更多的相同或者相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。
分治算法通常以数学归纳法来验证。而它的计算成本则多数以解递归关系式来判定。
分治算法是一个解决复杂问题的好工具,它可以把问题分解成若干个子问题,把子问题逐个解决,再组合到一起形成大问题的答案。比如,汉诺塔问题如果采用分治算法,可以把高度为n的塔的问题转换成高度为n-1的塔来解决,如此重复,直至问题化简到可以很容易的处理为止。
在每一层递归上都有三个步骤:
与数组相似,链表也是一种线性数据结构
单链表中的每个结点不仅包含值,还包含链接到下一个结点的引用字段。通过这种方式,单链表将所有结点按顺序组织起来。
与数组不同,无法在常量时间内访问单链表中的随机元素。如果想要获得第i个元素,必须从头结点逐个遍历。
cur
cur
的”next”字段链接到prev的下一个结点next
prev
中的”next”字段链到cur
与数组不同,不需要将所有元素移动到插入元素之后。因此,非常高效。
想从单链表中删除现有结点cur
,可以分两步完成:
prev
及其下一结点next
;prev
到cur的下一个结点next
如果想要删除第一个结点,可以简单地将下一个结点分配给head
。
给定一个链表,判断链表中是否有环
通过使用具有不同速度
的快、慢两个指针遍历链表,空间复杂度可以降低至1。慢指针每次移动一步,而快指针每次移动两步。
如果列表中不存在环,最终快指针将会最先到达尾部,此时我们可以返回false
。
不允许修改给定的链表
用一个Set
保存已经访问过的节点,可以遍历整个列表并返回第一个出现重复的节点。
算法:
首先,我们分配一个Set
去保存所有的列表节点。我们逐一遍历列表,检查当前节点是否出现过,如果节点已经出现过,那么一定形成了环且它是环的入口。否则如果有其他点是环的入口,我们应该先访问到其他节点而不是这个节点。其他情况,没有成环则直接返回 null 。
算法会在遍历有限个节点后终止,这是因为输入列表会被分成两类:成环的和不成环的。一个不成欢的列表在遍历完所有节点后会到达 null - 即链表的最后一个元素后停止。一个成环列表可以想象成是一个不成环列表将最后一个null
元素换成环的入口。
如果 while 循环终止,我们返回 null 因为我们已经将所有的节点遍历了一遍且没有遇到重复的节点,这种情况下,列表是不成环的。对于循环列表, while 循环永远不会停止,但在某个节点上, if 条件会被满足并导致函数的退出。
一种解决方案时按原始顺序迭代结点
,并将它们逐个移动到列表的头部
删除结点的步骤
三种方式:
想法
将奇节点放在一个链表里,偶链表放到另一个链表里。然后把偶链表接在奇链表的尾部
双链表以类似的方式工作,但还有一个引用字段
,称为prev
字段。有了这个额外的字段,就能够知道当前结点的前一结点。
可以与单链表相同的方式访问数据:
访问随机位置
。O(N)
,其中N
是链表的长度从双链表中删除一个现有的结点cur
,可以简单地将它的前一结点prev
与下一个结点next
链接起来。
O(N)
时间来找出前一结点prev
引用字段获取前一结点。因此可以在O(1)
时间内删除给定结点。给定一个整数数组,除了某个元素外其余元素均出现两次。请找出这个只出现一次的元素
答题思路:一个数组中除了一个元素,其他元素都出现两次,所以可以使用位运算异或来实现,因为相同的元素进行异或其结果为0
1 | class Solution { |
给定一个有序数组,需要原地删除其中重复内容,使每个元素只出现一次,并返回新的长度
不要另外定义一个数组,必须通过O(1)额外内存原地修改输入的数组来做到这一点
1 | class Solution { |
给定一个整数数列,找出其中和为特定值的那两个数
1 | 给定nums = [2, 7, 11, 15], target = 9 |
答题思路:
1 | class Solution { |
给定两个数组,写一个方法来计算它们的交集
例如:
给定nums1 = [1, 2, 2, 1], nums2 = [2, 2],返回[2, 2]
注意:
1 | class Solution { |
给定一个非负整数组成的非空数组,给整数加1
可以假设整数不包含任何前导零,除了数字0本身
最高位数字存放在列表的首位
1 | class Solution { |
给定一个整数数组,判断是否存在重复元素
如果任何值在数组中出现至少两次,函数应该返回true。如果每个元素都不相同,则返回false
1 | class Solution { |
编写一个函数,其功能是将输入的字符串反转过来
1 | class Solution { |
给定一个32位有符号整数,将整数中的数字进行反转
示例 1:
输入: 123
输出: 321
示例 2:
输入: -123
输出: -321
示例 3:
输入: 120
输出: 21
注意:
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1]。根据这个假设,如果反转后的整数溢出,则返回 0。
1 | class Solution { |
给定一个字符串,找到它的第一个不重复字符,并返回它的索引。如果不存在则返回-1
案例:
1 | s = "leetcode" |
注意事项:您可以假定该字符串只包含小写字母。
1 | class Solution { |
编写一个函数来查找字符串数组中的最长公共前缀
如果不存在最长公共前缀,返回空字符串””
1 | class Solution { |
给定两个字符串s和t,编写一个函数来判断t是否是s的一个字母异位词
s = “anagram”,t = “nagaram”,返回 true
s = “rat”,t = “car”,返回 false
注意:
假定字符串只包含小写字母。
提升难度:
输入的字符串包含 unicode 字符怎么办?你能能否调整你的解法来适应这种情况?
1 | class Solution { |
编写一个函数,使其可以删除某个链表中给定的(非末尾的)节点,只被给予要求被删的节点
比如:假设该链表为1 -> 2 -> 3 -> 4
,给定你的该链表值为3
的第三个节点,那么在调用了您的函数之后,该链表则应变成1 -> 2 ->4
1 | /** |
给定一个链表,删除链表的倒数第n个节点,并且返回链表的头结点
示例:
1 | 给定一个链表: 1->2->3->4->5,和n = 2 |
说明:
给定的n保证是有效的
进阶:
你能尝试使用一趟扫描实现吗?
1 | /** |
反转一个单链表
进阶:
链表可以迭代或递归地反转。你能够两个都实现一遍
1 | class Solution { |
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
1 | class Solution { |
在计算机科学中,二叉树是每个节点最多有两个树的树结构。通常子树被称作“左子树(left subtree)”和“右子树(right subtree)”。
二叉树的每个节点至多只有两棵子树(不存在度大于2的节点),二叉树的子树有左右之分,次序不能颠倒。
一棵深度为k,且有\(2^{k+1}-1\)个节点,称为k,有n个节点的二叉树,当且仅当其每一个节点都与深度为k的
满二叉树中,序号为1至n的节点对应时,称之为完全二叉树。
与树不同,树的节点个数至少为1,而二叉树的节点个数可以为0;树中节点的最大度数没有限制,而二叉树节点最大度数为2;
树的节点无左、右之分,而二叉树的节点有左、右之分。
二叉树是有个有根树,并且每个节点最多有2个子节点。非空的二叉树,若树叶总数为\(n_0\),分支度为2的总数
\(n_2\),则\(n_0=n_2+1\)
一棵深度为k,且有\(2^k-1\)个节点的二叉树,称为满二叉树。这种树的特点是每一层上的节点数都是最大节点数。
而在一棵二叉树中,除最后一层或者是满的,或者在右边缺少连续若干节点,则此二叉树为完全二叉树。