leetcode刷题

python刷题常用数据结构

引用自:https://blog.csdn.net/afterlake/article/details/100054150

我总结了一下自己在刷leetcode时关于python这个语言的经常被使用的数据结构和内置方法。

基础
离开数据结构,算法就是空中楼阁,所以了解python内置的数据类型用法和其效率是非常有必要的

list
list作为最常见的内置数据结构,其不仅可以当作C语言的数组来使用,一些python特有的特性往往可以事半功倍

append  在list的结尾追加一个元素

sort  对list进行排序,在list长度小的时候使用插入排序,在长度大的时候使用快排,所以其时间复杂度可以视为O(nlgn)

pop  将最后一个元素重list内部弹出并返回

切片  python强大的语法糖之一,不仅可以用非负数索引,负数索引的合理使用可以节省不少代码量

set
set本质是哈希表,会对其内部元素去重,检查一个元素是否在set内部的时间复杂度是O(1)

常用的方法为

add  添加一个元素,就算是用一个元素多次添加,其内部也仅保留一份

pop  随机弹出一个元素并返回

dict
同set一样,dict本质也是哈希表,但是set是单个元素,dict是key-value的组合

setdefault  接受两个入参key、default, 如果dict存在key则不做任何操作,如果不存在key,则创建一个 key其value为default

get  同setdefault一样接受两个参数key、default,如果存在key,则返回其value,否则返回default

pop 同setdefault一样接受两个参数key、default,如果存在key,则删除key返回其value,否则返回default

str
字符串也是一个经常在算法中常用的数据结构,在python中str是不可变对象,支持”+“操作当时效率不高需要慎用

split  用指定的分隔符将str分割为list

strip 返回str去掉首尾的空白符后新的str,原来的str不受影响

join 用str作为连接符连接参数里面的每一个元素,常常用来替代”+“

进阶
这里介绍几个常用的内置函数

int 将一个参数转为int类型,在遇到字母等字符时会抛出错误

sum 返回参数的求和

min 返回多个参数的最小值

max 返回多个参数的最大值

abs 返回一个数字的绝对值

高级
这里对于数据结构的知识点要求就比较高了,仅仅介绍常用方法,如果不了解其特性的还请自己查阅资料

queue 队列
put 入队操作

get 出队操作

list 栈
这里又有list,是因为python没有单独的栈,在需要栈的时候往往使用list

append 入栈

pop 出栈

heapq 堆
仅支持最小堆,有个小技巧:如果最大堆,取反之后再放入堆,取出的时候再取反

heapfiy  将一个list转为最小堆

heappush  往一个最小堆添加元素

heappop  弹出堆中的最小值并返回

 

题目:

给定 matrix =
[
[1,2,3],
[4,5,6],
[7,8,9]
],

原地旋转输入矩阵,使其变为:
[
[7,4,1],
[8,5,2],
[9,6,3]
]

class Solution(object):
    def rotate(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: None Do not return anything, modify matrix in-place instead.
        """
        length=len(matrix)
        ans=[]
        for i in range(length):
            row=[]
            for j in range(length):
                row.append(matrix[length-j-1][i])
            ans.append(row)
        matrix[:]=ans
        return matrix
View Code

 

字符串轮转。

给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成(比如,waterbottle是erbottlewat旋转后的字符串)。

示例1:

输入:s1 = "waterbottle", s2 = "erbottlewat"
输出:True

 

return len(s1) == len(s2) and s1 in s2*2

  

链表去重

编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。

示例1:

 输入:[1, 2, 3, 3, 2, 1]
 输出:[1, 2, 3]
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def removeDuplicateNodes(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head:
            return head
        history = set()
        # history = []
        temp = head
        while temp:
            if temp.val not in history:
                # history.append(temp.val)
                history.add(temp.val)
                pre = temp
                temp = temp.next
            else:
                pre.next = temp.next
                temp = temp.next

        return head
View Code

 

输出链表的倒数k个元素

暴力破解

class Solution(object):
    def kthToLast(self, head, k):
        """
        :type head: ListNode
        :type k: int
        :rtype: int
        """
        cur = head
        n = 0
        while cur.next:
            n += 1
            cur = cur.next
        c,cur2 = 0,head
        while c <= n-k:
            c += 1
            cur2 = cur2.next
        return cur2.val
View Code

 

机器人过关问题

输入:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
输出: [[0,0],[0,1],[0,2],[1,2],[2,2]]
解释:
输入中标粗的位置即为输出表示的路径,即
0行0列(左上角) -> 0行1列 -> 0行2列 -> 1行2列 -> 2行2列(右下角)

思路:递归,注意边界条件

# 递归算法
class Solution:
    def move(self, path, now, grid, r, c):                  # 传入递归变量path(保存正确路径),现在的位置,整个地图,以及地图大小(重复传入避免重复计算)
        print(now)
        if now==[r-1, c-1]:                                     # 递归终止条件: 现在在终点
            path.insert(0, now)                                     # 把当前位置(终点)插入正确路径的首位(因为它是第一个完成的所以插在首位,后面的位置都插在他前面)
            return True, now
        else:                                                   # 递归: 若不在终点
            if now[1]<=c-2 and grid[now[0]][now[1]+1]==0:           # 若当前位置的右边可行进(注意与可完成的区别),则
                next_op = [now[0], now[1]+1]                            # 下一步向右
                now_way = self.move(path, next_op, grid, r, c)          # 接受向右的结果
                if now_way[0]:                                              # 向右可到达(则当前位置可到达)
                    path.insert(0, now)                                     # 把当前位置插在历史记录的可到达路径的首位
                    return True, path
                elif now[0]<=r-2 and grid[now[0]+1][now[1]]==0:     # 若右方不可行进
                    next_op = [now[0]+1, now[1]]                        # 则尝试下方
                    now_way = self.move(path, next_op, grid, r, c)      # 接受向下的结果
                    if now_way[0]:                                          # 向下可到达(则当前位置可到达)
                        path.insert(0, now)                                 # 把当前位置插在历史记录的可到达路径的首位
                        return True, path
                    else:                                           # 若右方与下方均不可到达
                        return False,                                   # 则当前位置不可到达终点
                else:
                    return False, 
            elif now[0]<=r-2 and grid[now[0]+1][now[1]]==0:         # 若右方不可行进(如有障碍物或者到地图边缘)
                next_op = [now[0]+1, now[1]]                            # 下一步向下
                now_way = self.move(path, next_op, grid, r, c)
                if now_way[0]:
                    path.insert(0, now)
                    return True, path
                else:
                    return False, 
            else:                                                   # 若右方与下方均不可行进
                return False,                                           # 则当前位置不可到达

    def pathWithObstacles(self, obstacleGrid: List[List[int]]) -> List[List[int]]:
        r = len(obstacleGrid)
        c = len(obstacleGrid[0]) # 记录下地图的大小
        if r==1 and c==1:   # 如果是1x1直接返回结果
            if obstacleGrid[0][0]==0:
                return [[0, 0]]
            else:
                return []
        if obstacleGrid[0][0]==1 or obstacleGrid[r-1][c-1]==1: # 如果起点或者终点有障碍物则判否
            return []
        way = self.move([], [0, 0], obstacleGrid, r, c) # 递归运算,返回值是元组,way[0]表示是否存在路径,way[1]给出路径
        print(way)
        if way[0]:
            return way[1]
        else:
            return []
View Code

 

思路: 递归,从根开始

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def pathSum(self, root, sum):
        """
        :type root: TreeNode
        :type sum: int
        :rtype: int
        """
        self.ans = 0
        def f(node, vals):
            if node:
                vs = [i + node.val for i in vals] + [node.val]
                for i in range(len(vs)):
                    if vs[i] == sum:
                        self.ans += 1
                f(node.left, vs)
                f(node.right, vs)
        f(root, [])
        return self.ans
View Code

 

照样普通二分可以做

 两个等价
mid = (left + right) >> 1
mid = (left + right) /2


把循环的归类

编写一种方法,对字符串数组进行排序,将所有变位词组合在一起。变位词是指字母相同,但排列不同的字符串。

对于这种去重、分类问题,用sorted()排序之后就可以放入dict了

 

括号匹配问题:

括号。设计一种算法,打印n对括号的所有合法的(例如,开闭一一对应)组合。

说明:解集不能包含重复的子集。

例如,给出 n = 3,生成结果为:

[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]

class Solution(object):
    def generateParenthesis(self, n):
        """
        :type n: int
        :rtype: List[str]
        """
        re = []
        state = ''
        def dsp(state, p, q):       #p,q分别表示(和)还剩的个数,有个隐含条件:就是(在组合时候比)用的多或相等
            if p > q:               #非法,剪枝
                return 
            if q == 0:              #)用完之时
                re.append(state)
            
            if p > 0:
                dsp(state+'(', p-1, q)
            if q > 0:
                dsp(state+')', p, q-1)

        dsp(state, n, n)
        return re
View Code

 

 

 
posted @ 2020-04-27 23:56  TFknight  阅读(336)  评论(0编辑  收藏  举报