leetcode刷题-- 1. 双指针
这里的题是根据 CS-Notes里的顺序来一步步复习。
双指针
165两数之和 II - 输入有序数组
题目描述
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:
返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:
输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
题解(python)
class Solution(object):
def twoSum(self, numbers, target):
"""
:type numbers: List[int]
:type target: int
:rtype: List[int]
"""
if (numbers == None):
return None
i = 0
j = len(numbers)-1
while(i<j):
s = numbers[i] + numbers[j]
if ( s == target):
return [i+1,j+1]
elif(s < target):
i = i + 1
else:
j = j - 1
return [-1,-1]
1 两数之和 (这道不是双指针,一遍哈希表)
题目描述
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
题解
# 用一遍哈希表,也就是python里的字典
# 将每个数先存进去,相同的key,会因为hash_map[n]=i这句而覆盖掉,边存便判断hash_map里是否存在满足条件的key
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
hash_map = {}
for i,n in enumerate(nums):
if (target-n) in hash_map.keys():
return [hash_map[target-n], i]
hash_map[n] = i
return [-1,-1]
633平方数之和
题目描述
给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c。
示例1:
输入: 5
输出: True
解释: 1 * 1 + 2 * 2 = 5
示例2:
输入: 3
输出: False
题解
class Solution:
def judgeSquareSum(self, c: int) -> bool:
i = 0
j = int(math.sqrt(c))
while(i<=j):
s = i*i + j*j
if(s == c):
return True
elif(s > c):
j = j - 1
else:
i = i + 1
return False
680验证回文字符串 Ⅱ
题目描述
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
示例 1:
输入: "aba"
输出: True
示例 2:
输入: "abca"
输出: True
解释: 你可以删除c字符。
注意:
字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。
题解
解法一
class Solution:
def validPalindrome(self, s: str) -> bool:
if(s[::-1] == s):
return True
else:
n = len(s)
i,j = 0,n-1
while(i<j):
if(s[i]==s[j]):
i += 1
j -= 1
continue
else:
a = s[i+1:j+1]
b = s[i:j]
return a[::-1]==a or b[::-1] == b
解法二
class Solution:
def validPalindrome(self, s: str) -> bool:
if s == s[::-1]:
return True
i,j = 0, len(s) - 1
while i<j:
if s[i]==s[j]:
i, j = i+1, j-1
else:
a = s[i+1: j+1]
b = s[i: j]
return a == a[::-1] or b == b[::-1]
python里判断回文很简单a == a[::-1]就行,而这里我发现a[::-1] == a比 a == a[::-1]要耗时更多。
这道题关键就是删去一个字符
88合并两个有序数组
题目描述
给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。
说明:
初始化 nums1 和 nums2 的元素数量分别为 m 和 n。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例:
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
题解
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
i,j,k = m-1, n-1, m+n-1
while i>=0 or j>=0:
if i<0:
nums1[k] = nums2[j]
k -= 1
j -= 1
elif j<0:
nums1[k] = nums1[i]
k -= 1
i -= 1
elif nums1[i] > nums2[j]:
nums1[k] = nums1[i]
k -= 1
i -= 1
else:
nums1[k] = nums2[j]
k -= 1
j -= 1
# 另一种32 ms
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
p1=m-1
p2=n-1
p=m+n-1
while p1>=0 and p2>=0:
if nums1[p1]>nums2[p2]:
nums1[p]=nums1[p1]
p1-=1
else:
nums1[p]=nums2[p2]
p2-=1
p-=1
print(p2)
if p2>=0:
nums1[:p2+1]=nums2[:p2+1]
难点在于从后开始往前扫。这个32ms的例子的思想在于:p每移动一格,p1或p2肯定会移动一格去替换掉p处的值,当p1或者p2变成-1移到末尾时,分两种情况:
- p1 为 -1, 这时将nums2剩下元素填入即nums1[:p2+1] = nums2[:p2+1]
- p2 为 -1, 这时nums1剩下元素基本不用动。
- 或者考虑两种极端情况:nums1 = [1,2,3,0,0,0] nums2= [4,5,6]; nums1 = [4,5,6,0,0,0] nums2 = [1,2,3]也是如此
141环形链表
题目描述
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
题解
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head: ListNode) -> bool:
# 问题在于NoneType没有next这个attribute
if head == None:
return False
l,r = head, head.next
while r!=None and r.next!=None:
if l==r:
return True
else:
l = l.next
r = r.next.next
return False
使用双指针,快慢指针。一个指针每次移动一个节点,一个指针每次移动两个节点,如果存在环,那么这两个指针一定会相遇。
一开始l,r分别初始化为head和head.next,l走得慢,r走得快。如果在前走的快的r还与l相遇了,那么肯定存在环。
这里的r只需要判断r和r.next不为None就可以了。判断r的目的是为了r.next不报错不然r.next直接报错。
需注意,一开始给l,r赋值之前要判断下head是否为None,不然head.next直接报错。
*142环形链表 II(附加题,熟悉下链表)
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。
题解
一开始没想出来,参考讨论区里的解法
解题思路:
- 这类链表题目一般都是使用双指针法解决的,例如寻找距离尾部第K个节点、寻找环入口、寻找公共尾部入口等。
算法流程:
双指针第一次相遇: 设两指针 fast,slow 指向链表头部 head,fast 每轮走 22 步,slow 每轮走 11 步;
- 第一种结果: fast 指针走过链表末端,说明链表无环,直接返回 null;
- TIPS: 若有环,两指针一定会相遇。因为每走 1 轮,fast 与 slow 的间距 +1,fast 终会追上 slow;
- 第二种结果: 当fast == slow时, 两指针在环中 第一次相遇 。下面分析此时fast 与 slow走过的 步数关系 :
- 设链表共有 a+b 个节点,其中 链表头部到链表入口 有 a个节点(不计链表入口节点), 链表环 有 b 个节点(这里需要注意,a 和 b 是未知数,例如图解上链表 a=4,b=5b=5);设两
指针分别走了 ff,ss 步,则有:
- fast 走的步数是slow步数的 2 倍,即 f = 2s;(解析: fast 每轮走 2 步)
- fast 比 slow多走了 n 个环的长度,即 f = s + nb;( 解析: 双指针都走过 a 步,然后在环内绕圈直到重合,重合时 fast 比 slow 多走环的长度整数倍 );
- 以上两式相减得:f = 2nb,s = nb,即fast和slow 指针分别走了 2n,n 个 环的周长 (注意: n 是未知数,不同链表的情况不同)。
- 设链表共有 a+b 个节点,其中 链表头部到链表入口 有 a个节点(不计链表入口节点), 链表环 有 b 个节点(这里需要注意,a 和 b 是未知数,例如图解上链表 a=4,b=5b=5);设两
- 第一种结果: fast 指针走过链表末端,说明链表无环,直接返回 null;
目前情况分析::
- 如果让指针从链表头部一直向前走并统计步数k,那么所有 走到链表入口节点时的步数 是:k=a+nb(先走 a 步到入口节点,之后每绕 1 圈环( b 步)都会再次到入口节点)。
- 而目前,slow 指针走过的步数为 nb 步。因此,我们只要想办法让 slow 再走 a 步停下来,就可以到环的入口。
- 但是我们不知道 a 的值,该怎么办?依然是使用双指针法。我们构建一个指针,此指针需要有以下性质:此指针和slow 一起向前走 a 步后,两者在入口节点重合。那么从哪里走到入口节点需
要 a 步?答案是链表头部head。
双指针第二次相遇:
- slow指针 位置不变 ,将fast指针重新 指向链表头部节点 ;slow和fast同时每轮向前走 11 步;
- TIPS:此时 f = 0f=0,s = nbs=nb ;
- 当 fast 指针走到f = af=a 步时,slow 指针走到步s = a+nbs=a+nb,此时 两指针重合,并同时指向链表环入口 。
- slow指针 位置不变 ,将fast指针重新 指向链表头部节点 ;slow和fast同时每轮向前走 11 步;
返回slow指针指向的节点。
复杂度分析:
时间复杂度 O(N):第二次相遇中,慢指针须走步数 a < a + b;第一次相遇中,慢指针须走步数 a + b - x < a + b,其中 x 为双指针重合点与环入口距离;因此总体为线性复杂度;
空间复杂度 O(1):双指针使用常数大小的额外空间。
当走了a+nb时,位置为入口处;而第一次相遇后慢指针走的距离为nb,注意这两个n不相等,但nb再走a步就到了入口处,这时我们可以另设一个指针从head处走,每次一步,那么他就会与慢指针在入口处相遇。
题解
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
fast, slow = head, head
while True:
if not(fast and fast.next):
return
fast, slow = fast.next.next, slow.next
if fast == slow:
break
fast = head
while fast!=slow:
fast = fast.next
slow = slow.next
return slow
这里我之前在while里判断fast != None and fast.next != None,这样造成的问题就是判断为False时,我的返回一个空说明没环,不好写。所以判断最好还是在if里,循环用while True。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
if head == None:
return None
fast, slow = head, head
if fast.next!=None:
fast = fast.next.next
slow = slow.next
while fast != None and fast.next != None:
if fast!=slow:
fast = fast.next.next
slow = slow.next
else:
fast = head
while fast!=slow:
fast = fast.next
slow = slow.next
return slow
return None
524通过删除字母匹配到字典里最长单词
题目描述
给定一个字符串和一个字符串字典,找到字典里面最长的字符串,该字符串可以通过删除给定字符串的某些字符来得到。如果答案不止一个,返回长度最长且字典顺序最小的字符串。如果答案不存在,则返回空字符串。
示例 1:
输入:
s = "abpcplea", d = ["ale","apple","monkey","plea"]
输出:
"apple"
示例 2:
输入:
s = "abpcplea", d = ["a","b","c"]
输出:
"a"
说明:
- 所有输入的字符串只包含小写字母。
- 字典的大小不会超过 1000。
- 所有输入的字符串长度不会超过 1000。
题解
def isSubStr(s:str, t:str):
#第一种,双指针
# l1,l2 = len(s), len(t)
# if l1 < l2:
# return False
# i,j = 0,0
# while (i<l1 and j<l2):
# if (s[i] != t[j]):
# i += 1
# else:
# i += 1
# j += 1
# return j == l2
#第二种
for i in t:
if i in s:
s = s[s.index(i)+1:]
else:
return False
return True
class Solution:
def findLongestWord(self, s: str, d: List[str]) -> str:
d.sort()
res = ''
if d:
for i in d:
if (len(i) < len(res) or (len(i)==len(res) and res < i)):
continue
else:
if (isSubStr(s, i)):
res = i
return res
另外一种方法,先将d进行按照len进行降序排序,每一个元素那么最长的排最前面,短的后面~同样长的,就按照字典顺序:a<b<c<d这种排列。所以它不需要遍历d种所有元素
leetcode刷题-- 1. 双指针的更多相关文章
- LeetCode刷题总结-双指针、位运算和分治法篇
本文总结LeetCode上有关双指针.位运算和分治法的算法题,推荐刷题总数14道.具体考点分析如下图: 一.双指针 1.字符串和数组问题 题号:424. 替换后的最长重复字符,难度中等 题号:828. ...
- Leetcode刷题笔记(双指针)
1.何为双指针 双指针主要用来遍历数组,两个指针指向不同的元素,从而协同完成任务.我们也可以类比这个概念,推广到多个数组的多个指针. 若两个指针指向同一数组,遍历方向相同且不会相交,可以称之为滑动窗口 ...
- C#LeetCode刷题-双指针
双指针篇 # 题名 刷题 通过率 难度 3 无重复字符的最长子串 24.5% 中等 11 盛最多水的容器 43.5% 中等 15 三数之和 16.1% 中等 16 最接近的三数之和 3 ...
- LeetCode刷题总结之双指针法
Leetcode刷题总结 目前已经刷了50道题,从零开始刷题学到了很多精妙的解法和深刻的思想,因此想按方法对写过的题做一个总结 双指针法 双指针法有时也叫快慢指针,在数组里是用两个整型值代表下标,在链 ...
- LeetCode刷题总结-数组篇(上)
数组是算法中最常用的一种数据结构,也是面试中最常考的考点.在LeetCode题库中,标记为数组类型的习题到目前为止,已累计到了202题.然而,这202道习题并不是每道题只标记为数组一个考点,大部分习题 ...
- LeetCode刷题总结-数组篇(下)
本期讲O(n)类型问题,共14题.3道简单题,9道中等题,2道困难题.数组篇共归纳总结了50题,本篇是数组篇的最后一篇.其他三个篇章可参考: LeetCode刷题总结-数组篇(上),子数组问题(共17 ...
- LeetCode刷题的一点个人建议和心得
目录 1. 为什么我们要刷LeetCode? 2. LeetCode的现状和问题 3. 本文的初衷 4. LeetCode刷题建议 4.1入门数据结构,打基础阶段 4.2 建立 ...
- 看完互联网大佬的「LeetCode 刷题手册」, 手撕了 400 道 Leetcode 算法题
大家好,我是 程序员小熊 ,来自 大厂 的程序猿.相信绝大部分程序猿都有一个进大厂的梦想,但相较于以前,目前大厂的面试,只要是研发相关岗位,算法题基本少不了,所以现在很多人都会去刷 Leetcode ...
- LeetCode刷题模板(1):《我要打10个》之二分法
Author : 叨陪鲤 Email : vip_13031075266@163.com Date : 2021.01.23 Copyright : 未 ...
随机推荐
- markdown区块
Markdown 区块 Markdown 区块引用是在段落开头使用 > 符号 ,然后后面紧跟一个空格符号: > 区块引用 > 菜鸟教程 > 学的不仅是技术更是梦想 显示结果如下 ...
- yii2.0 ajax
2.0用的参数是_csrf token = "<?php echo \Yii::$app->request->getCsrfToken()?>", $.aj ...
- 【PAT甲级】1093 Count PAT's (25 分)
题意: 输入一行由大写字母'P','A','T',组成的字符串,输出一共有多少个三元组"PAT"(相对顺序为PAT即可),答案对1e9+7取模. AAAAAccepted code ...
- 【C语言】找出1000以内的水仙花数
什么是水仙花数? 水仙花数是指一个 3 位数,它的每个位上的数字的 3次幂之和等于它本身(例如:1^3 + 5^3+ 3^3 = 153). 代码1: #include<stdio.h> ...
- Python分析盘点2019全球流行音乐:是哪些歌曲榜单占领了我们?
写在前面:圣诞刚过,弥留者节日气息的大家是否还在继续学习呐~在匆忙之际也不忘给自己找几首好听的歌曲放松一下,缠绕着音乐一起来看看关于2019年流行音乐趋势是如何用Python分析的吧! 昨天下午没事儿 ...
- 关于SQL
set nocount on 作用 阻止在结果集中返回显示受t-sql语句影响的行计数信息 set nocount on 不返回计数,set nocount off 返回计数 即使当set nocou ...
- WordPress搭建教程---购买域名+购买VPS主机+域名DNS解析+网站环境+上传网站程序
WordPress搭建教程 购买域名---NameSilo 购买VPS主机---Vultr 域名DNS解析 网站环境 上传网站程序 参考文章: 1. WordPress搭建教程 https://zhu ...
- js中的跨域
因为javascript的同源策略,导致它普通情况下不能跨域,直到现在,我还是不能完全理解js跨域的几种方法,没办法,只能慢慢学习,慢慢积累,这不,几天又在园里看到一篇博文,有所收获,贴上来看看; 原 ...
- 忘记linux下的mysql密码,需要重新创建密码123456
你必须要有操作系统的root权限了. # mysqld_safe --skip-grant-tables & &,表示在后台运行,不再后台运行的话,就再打开一个终端咯. # mysql ...
- eclipse 查看项目svn路径
1. window -- show view -- other -- svn -- svn资源库 2. 右键 -- properties 3.复制路径,打开TortoiseSvn -- Repo br ...