一、两数之和
题目描述
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。 你可以按任意顺序返回答案。
示例
示例 1: 输入:nums = [2,7,11,15], target = 9 输出:[0,1] 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。 示例 2: 输入:nums = [3,2,4], target = 6 输出:[1,2] 示例 3: 输入:nums = [3,3], target = 6 输出:[0,1]
解题
class Solution(object): def twoSum(self, nums, target): """ :type nums: List[int] :type target: int :rtype: List[int] """ hash_dict = {} for i, num in enumerate(nums): if target - num in hash_dict: return [i, hash_dict[target - num]] else: hash_dict[num] = i return []
思路:
- 建一个字典。
- 使用enumerate方法for循环数组,可以循环出数组的下标、元素。
- 在for循环中,判断元素是否在字典的key中,当字典key里出现target-num,说明当前的num即为另一个加数。
如果不存在,那么就放到dict里,key是元素,value是下标。 - 此时,取出当前for循环的i,和另一个加数在dict里的value,组成数组返回。
二、有效的括号
题目描述
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。 有效字符串需满足: 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。
示例
示例 1: 输入:s = "()" 输出:true 示例 2: 输入:s = "()[]{}" 输出:true 示例 3: 输入:s = "(]" 输出:false 示例 4: 输入:s = "([)]" 输出:false 示例 5: 输入:s = "{[]}" 输出:true
解题
class Solution: def isValid(self, s: str) -> bool: if len(s) % 2 == 1: return False pairs_dict = { ")": "(", "]": "[", "}": "{" } stack_list = [] for ch in s: if stack_list and ch in pairs_dict: if stack_list[-1] == pairs_dict[ch]: stack_list.pop() else: return False else: stack_list.append(ch) return not stack_list
解题思路:利用栈的实现思路。
- for循环字符串
- 前面的元素 先放进列表
- 当列表不为空,而且最后面的元素存在 dict的key里,说明可以组成一对括号,就把元素剔除。
- for循环结束,列表为空说明全部都可以组成括号。
比如测试输入"{()[()]}"
,列表里的过程是这样的:
列表的内容: ['{'] 列表的内容: ['{', '('] 列表的内容: ['{'] 列表的内容: ['{', '['] 列表的内容: ['{', '[', '('] 列表的内容: ['{', '['] 列表的内容: ['{'] 列表的内容: []
这也是为什么在上面字典里存放的k-v,是")": "("
而不是"(": ")"
,因为判断后面的元素是用的字段里的key,
所以右括号放在了前面。
三、二分查找
题目描述
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例
示例 1: 输入: nums = [-1,0,3,5,9,12], target = 9 输出: 4 解释: 9 出现在 nums 中并且下标为 4 示例 2: 输入: nums = [-1,0,3,5,9,12], target = 2 输出: -1 解释: 2 不存在 nums 中因此返回 -1
解题
class Solution: def search(self, nums: List[int], target: int) -> int: left = 0 right = len(nums) - 1 while left <= right: mid = left + (right - left) // 2 if nums[mid] == target: return mid if target < nums[mid]: right = mid - 1 else: left = mid + 1 return -1
二分查找:
- 初始化左、右两个指针,分别为
left=0
,right=len(nums) - 1
。 - while循环,当
left<right
,进行二分计算,找到中间值mid=left + (right-left) // 2
- 在每次的循环里,用计算出来的mid与目标值target进行比较,三种情况:
mid == target
,说明找到了,返回mid
mid > target
,那么左指针left
不用动,右指针right = mid-1
mid < target
, 那么右指针right
不用动,左指针left = mid+1
上述为列表中顺序从小到大。
如果列表是从大到小,变动点在于mid与target的大小判断后,
左右指针的移动情况:
mid == target
,说明找到了,返回mid
mid > target
,那么右指针right
不用动,左指针left = mid+1
mid < target
,那么左指针left
不用动,右指针right = mid-1
四、环形链表
题目描述
给定一个链表,判断链表中是否有环。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。 如果链表中存在环,则返回 true 。 否则,返回 false 。
示例
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。
解题
# 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: seen = set() while head: if head in seen: return True seen.add(head) head = head.next return False
从简单角度看,可以遍历所有的结点,判断这个结点之前是否访问过。
使用哈希表存放已经访问过的结点。在python里,dict()和set()都是基于哈希表的数据结构。
- 创建set()
- while循环
- 每次循环里,判断当前结点是否在set()里。如果存在,返回True;
- 如果不存在,就把当前结点add增加到set()里,然后当前指针指向下一个结点
head = head.next
五、用栈实现队列
题目描述
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty): 实现 MyQueue 类: void push(int x) 将元素 x 推到队列的末尾 int pop() 从队列的开头移除并返回元素 int peek() 返回队列开头的元素 boolean empty() 如果队列为空,返回 true ;否则,返回 false 说明: 你只能使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
示例
输入: ["MyQueue", "push", "push", "peek", "pop", "empty"] [[], [1], [2], [], [], []] 输出: [null, null, null, 1, 1, false] 解释: MyQueue myQueue = new MyQueue(); myQueue.push(1); // queue is: [1] myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue) myQueue.peek(); // return 1 myQueue.pop(); // return 1, queue is [2] myQueue.empty(); // return false
解题
from collections import deque class MyQueue: def __init__(self): """ Initialize your data structure here. """ self.deque_nums = deque([]) def push(self, x: int) -> None: """ Push element x to the back of queue. """ self.deque_nums.append(x) def pop(self) -> int: """ Removes the element from in front of queue and returns that element. """ return self.deque_nums.popleft() def peek(self) -> int: """ Get the front element. """ return self.deque_nums[0] def empty(self) -> bool: """ Returns whether the queue is empty. """ if len(self.deque_nums) == 0: return True else: return False # Your MyQueue object will be instantiated and called as such: # obj = MyQueue() # obj.push(x) # param_2 = obj.pop() # param_3 = obj.peek() # param_4 = obj.empty()
这里使用的是python中的collections
库,其中deque
方法实现了双端队列,以前在博客有过相关整理。
deque除了实现list的append()
和pop()
外,还提供了appendleft()
和popleft()
,
这样的话我们可以很方便的向着列表的另一头,进行添加和移除操作了
这里重点就是在于pop
方法的实现,队列是要保证先进先出的。比如在列表里[1,2,3,4]
,那么
出队的时候,顺序应该也是从前到后一次,所以要求每次出队操作是删除列表第一个元素,所以用
deque_nums.popleft()