这里的题是根据 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个节点、寻找环入口、寻找公共尾部入口等。

算法流程:

  1. 双指针第一次相遇: 设两指针 fast,slow 指向链表头部 head,fast 每轮走 22 步,slow 每轮走 11 步;

    1. 第一种结果: fast 指针走过链表末端,说明链表无环,直接返回 null;

      • TIPS: 若有环,两指针一定会相遇。因为每走 1 轮,fast 与 slow 的间距 +1,fast 终会追上 slow;
    2. 第二种结果: 当fast == slow时, 两指针在环中 第一次相遇 。下面分析此时fast 与 slow走过的 步数关系 :
      • 设链表共有 a+b 个节点,其中 链表头部到链表入口 有 a个节点(不计链表入口节点), 链表环 有 b 个节点(这里需要注意,a 和 b 是未知数,例如图解上链表 a=4,b=5b=5);设两

        指针分别走了 ff,ss 步,则有:
      1. fast 走的步数是slow步数的 2 倍,即 f = 2s;(解析: fast 每轮走 2 步)
      2. fast 比 slow多走了 n 个环的长度,即 f = s + nb;( 解析: 双指针都走过 a 步,然后在环内绕圈直到重合,重合时 fast 比 slow 多走环的长度整数倍 );
      • 以上两式相减得:f = 2nb,s = nb,即fast和slow 指针分别走了 2n,n 个 环的周长 (注意: n 是未知数,不同链表的情况不同)。
  2. 目前情况分析::

    • 如果让指针从链表头部一直向前走并统计步数k,那么所有 走到链表入口节点时的步数 是:k=a+nb(先走 a 步到入口节点,之后每绕 1 圈环( b 步)都会再次到入口节点)。
    • 而目前,slow 指针走过的步数为 nb 步。因此,我们只要想办法让 slow 再走 a 步停下来,就可以到环的入口。
    • 但是我们不知道 a 的值,该怎么办?依然是使用双指针法。我们构建一个指针,此指针需要有以下性质:此指针和slow 一起向前走 a 步后,两者在入口节点重合。那么从哪里走到入口节点需

      要 a 步?答案是链表头部head。
  3. 双指针第二次相遇:

    • slow指针 位置不变 ,将fast指针重新 指向链表头部节点 ;slow和fast同时每轮向前走 11 步;

      • TIPS:此时 f = 0f=0,s = nbs=nb ;
    • 当 fast 指针走到f = af=a 步时,slow 指针走到步s = a+nbs=a+nb,此时 两指针重合,并同时指向链表环入口 。
  4. 返回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"

说明:

  1. 所有输入的字符串只包含小写字母。
  2. 字典的大小不会超过 1000。
  3. 所有输入的字符串长度不会超过 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. 双指针的更多相关文章

  1. LeetCode刷题总结-双指针、位运算和分治法篇

    本文总结LeetCode上有关双指针.位运算和分治法的算法题,推荐刷题总数14道.具体考点分析如下图: 一.双指针 1.字符串和数组问题 题号:424. 替换后的最长重复字符,难度中等 题号:828. ...

  2. Leetcode刷题笔记(双指针)

    1.何为双指针 双指针主要用来遍历数组,两个指针指向不同的元素,从而协同完成任务.我们也可以类比这个概念,推广到多个数组的多个指针. 若两个指针指向同一数组,遍历方向相同且不会相交,可以称之为滑动窗口 ...

  3. C#LeetCode刷题-双指针

    双指针篇 # 题名 刷题 通过率 难度 3 无重复字符的最长子串   24.5% 中等 11 盛最多水的容器   43.5% 中等 15 三数之和   16.1% 中等 16 最接近的三数之和   3 ...

  4. LeetCode刷题总结之双指针法

    Leetcode刷题总结 目前已经刷了50道题,从零开始刷题学到了很多精妙的解法和深刻的思想,因此想按方法对写过的题做一个总结 双指针法 双指针法有时也叫快慢指针,在数组里是用两个整型值代表下标,在链 ...

  5. LeetCode刷题总结-数组篇(上)

    数组是算法中最常用的一种数据结构,也是面试中最常考的考点.在LeetCode题库中,标记为数组类型的习题到目前为止,已累计到了202题.然而,这202道习题并不是每道题只标记为数组一个考点,大部分习题 ...

  6. LeetCode刷题总结-数组篇(下)

    本期讲O(n)类型问题,共14题.3道简单题,9道中等题,2道困难题.数组篇共归纳总结了50题,本篇是数组篇的最后一篇.其他三个篇章可参考: LeetCode刷题总结-数组篇(上),子数组问题(共17 ...

  7. LeetCode刷题的一点个人建议和心得

    目录 1.    为什么我们要刷LeetCode? 2.    LeetCode的现状和问题 3.    本文的初衷 4.    LeetCode刷题建议 4.1入门数据结构,打基础阶段 4.2 建立 ...

  8. 看完互联网大佬的「LeetCode 刷题手册」, 手撕了 400 道 Leetcode 算法题

    大家好,我是 程序员小熊 ,来自 大厂 的程序猿.相信绝大部分程序猿都有一个进大厂的梦想,但相较于以前,目前大厂的面试,只要是研发相关岗位,算法题基本少不了,所以现在很多人都会去刷 Leetcode ...

  9. LeetCode刷题模板(1):《我要打10个》之二分法

    Author       :  叨陪鲤 Email         : vip_13031075266@163.com Date          : 2021.01.23 Copyright : 未 ...

随机推荐

  1. markdown区块

    Markdown 区块 Markdown 区块引用是在段落开头使用 > 符号 ,然后后面紧跟一个空格符号: > 区块引用 > 菜鸟教程 > 学的不仅是技术更是梦想 显示结果如下 ...

  2. yii2.0 ajax

    2.0用的参数是_csrf token = "<?php echo \Yii::$app->request->getCsrfToken()?>", $.aj ...

  3. 【PAT甲级】1093 Count PAT's (25 分)

    题意: 输入一行由大写字母'P','A','T',组成的字符串,输出一共有多少个三元组"PAT"(相对顺序为PAT即可),答案对1e9+7取模. AAAAAccepted code ...

  4. 【C语言】找出1000以内的水仙花数

    什么是水仙花数? 水仙花数是指一个 3 位数,它的每个位上的数字的 3次幂之和等于它本身(例如:1^3 + 5^3+ 3^3 = 153). 代码1: #include<stdio.h> ...

  5. Python分析盘点2019全球流行音乐:是哪些歌曲榜单占领了我们?

    写在前面:圣诞刚过,弥留者节日气息的大家是否还在继续学习呐~在匆忙之际也不忘给自己找几首好听的歌曲放松一下,缠绕着音乐一起来看看关于2019年流行音乐趋势是如何用Python分析的吧! 昨天下午没事儿 ...

  6. 关于SQL

    set nocount on 作用 阻止在结果集中返回显示受t-sql语句影响的行计数信息 set nocount on 不返回计数,set nocount off 返回计数 即使当set nocou ...

  7. WordPress搭建教程---购买域名+购买VPS主机+域名DNS解析+网站环境+上传网站程序

    WordPress搭建教程 购买域名---NameSilo 购买VPS主机---Vultr 域名DNS解析 网站环境 上传网站程序 参考文章: 1. WordPress搭建教程 https://zhu ...

  8. js中的跨域

    因为javascript的同源策略,导致它普通情况下不能跨域,直到现在,我还是不能完全理解js跨域的几种方法,没办法,只能慢慢学习,慢慢积累,这不,几天又在园里看到一篇博文,有所收获,贴上来看看; 原 ...

  9. 忘记linux下的mysql密码,需要重新创建密码123456

    你必须要有操作系统的root权限了. # mysqld_safe --skip-grant-tables & &,表示在后台运行,不再后台运行的话,就再打开一个终端咯. # mysql ...

  10. eclipse 查看项目svn路径

    1. window -- show view -- other -- svn -- svn资源库 2. 右键 -- properties 3.复制路径,打开TortoiseSvn -- Repo br ...