Test101_zxy

 

注:部分思路也被体现在代码注释中!

第1题:

方法(1):直接调用find()内置函数返回索引

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
       return haystack.find(needle)

方法(2):从索引0开始匹配,每次在 haystack串中将长度为len(needle)的子串和needle匹配

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        # if not needle:
        #     return 0
        n, m = len(haystack), len(needle)
        # i代表着起点位置
        for i in range(n - m + 1):
            # 标识外层循环一次的结果
            flag = True
            for j in range(m):
                # 对应位置字符不匹配,匹配失败
                if haystack[i + j] != needle[j]:
                    flag = False
                    break
            if flag:
                return i
        # 全部循环结束,没有返回索引代表匹配失败
        return -1

第2题:

方法(1):调用split()函数将字符串切分为仅包含字符串的列表,返回列表最后位置的字符串长度

class Solution:
    def lengthOfLastWord(self, s: str) -> int:
        temp = s.split()
        return len(temp[-1])
        

 

方法(2):从末尾搜索第一个不为空串的字符即为最后一个字符的末尾,再从此位置搜索到 第一个为空串的索引,相减即长度

class Solution:
    def lengthOfLastWord(self, s: str) -> int:
       # 求最后一个单词结束字符的下标
        end = len(s) - 1
        while end >= 0 and s[end] == " ":
            end -=1
        if end < 0:
            return 0
        # 求最后一个单词开始字符的下标
        start = end
        while s[start] != " " and start >= 0:
            start -= 1
        return end - start

 第3题:

回文串的正序和逆序是完全相同的

方法(1):遍历字符串,将字母或数字转小写后扔进列表,判断列表的逆序和正序是否相同

class Solution:
    def isPalindrome(self, s: str) -> bool:
        if not s:
            return True
        temp = []
        for i in s:
            if i.isalnum():
                temp.append(i.lower())
        return temp == temp[::-1]

方法(2):双指针,从两头判断指针所指位置的字符是否相同 

class Solution:
    def isPalindrome(self, s: str) -> bool:
        # 两端判断
        if not s:
            return True

        l,r = 0,len(s)-1
        while l < r:
            while l < r and not s[l].isalnum():
                l += 1
            while l < r and not s[r].isalnum():
                r -= 1
            if l < r:
                if s[l].lower() != s[r].lower():
                    return False
                else:
                    l,r = l+1,r-1
        return True

第4题:

思路:遍历矩阵,判断每个元素是否和左上角相等

class Solution:
    def isToeplitzMatrix(self, matrix) -> bool:
        for i in range(1,len(matrix)):
            for j in range(1,len(matrix[0])):
                # 注意边界条件 i-1,j-1;所以i,j都从1开始
                if matrix[i][j] != matrix[i-1][j-1]:
                    return False
        return True


第5题:

思路:利用前缀和,要求左侧等于右侧,即2倍的前缀和=数组总和total-nums[i]

class Solution:
    def pivotIndex(self, nums) -> int:
        total = sum(nums)
        temp = 0
        for i in range(len(nums)):
            if nums[i] + 2*temp == total:
                return i
            temp += nums[i]
        return -1
            

第6题: 

思路:利用位运算,从n的末尾开始,将当前位左移31-i位,求累加,具体见注释

class Solution:
    def reverseBits(self, n: int) -> int:
        # 位运算
        # n & 1 做与运算表示取出n的最后一位
        # n >> i 表示n右移i位
        res = 0
        for i in range(32):
            temp = (n >> i) & 1
            # 把二进制个位左移 31-i位,相当于翻转操作
            res += temp << (31-i)
        return res

 第7题:

方法(1):将其中一个字符串遍历加入列表,再对另一个串遍历,每次删除列表中相同字符,判断字符是否存在和最后列表是否为空

class Solution:
    def isAnagram(self, s: str, t: str):
        # 单一匹配
        temp = []
        for i in s:
            temp.append(i)
        for j in t:
            if j in temp:
                temp.remove(j)
            else:return False
        return len(temp) == 0

方法(2):利用内置函数counter,判断词频字典是否相等

from collections import Counter
class Solution:
    def isAnagram(self, s: str, t: str):
        return Counter(s) == Counter(t)

 

 第8题:

思路:一个栈做入队,一个栈做出队,具体见代码注释

class MyQueue:

    def __init__(self):
        # 入队栈
        self.temp1 = []
        # 出队栈
        self.temp2 = []


    def push(self, x: int) -> None:
        self.temp1.append(x)


    def pop(self) -> int:
        # 出队时,先从出队栈出,出队栈为空则通过入队栈添值
        if self.temp2:
            return self.temp2.pop()
        while self.temp1:
            self.temp2.append(self.temp1.pop())
        return self.temp2.pop()



    def peek(self) -> int:
        # 队首同出队
        if self.temp2:
            return self.temp2[-1]
        while self.temp1:
            self.temp2.append(self.temp1.pop())
        return self.temp2[-1]



    def empty(self) -> bool:
        # 只有两个栈全为空,队才空
        return len(self.temp1) == 0 and len(self.temp2) == 0

第9题:

思路:双指针,从头匹配,匹配成功两个指针都后移一位,失败则待匹配串指针后移一位

class Solution:
    def isSubsequence(self, s: str, t: str) -> bool:
        # 双指针
        i = j = 0
        while i < len(s) and j < len(t):
            if s[i] == t[j]:
                i += 1
                j += 1
            else:j += 1
        return i == len(s)

第10题: 

 思路:二分查找,把区间一分为2,比中间值大则在后半部分二分,小则在前部分二分

# The guess API is already defined for you.
# @param num, your guess
# @return -1 if my number is lower, 1 if my number is higher, otherwise return 0
# def guess(num: int) -> int:

class Solution:
    def guessNumber(self, n: int) -> int:
        l,r = 1,n
        while l < r:
            mid = (l+r) // 2
            flag = guess(mid)
            if flag == 0:
                return mid
            if flag == -1:
                r = mid - 1
            else:l = mid + 1
        return l

第11题:

思路:dp[i][j]代表着区间[i,j]赢得游戏至少需要的现金,比如dp[1][1] = 0,代表着区间长度为1的[1,1]区间赢得游戏至少需要0元。要想知道某种len=2的情况下所需要的最少现金,必须要知道所有len=1情况下的现金状况,以此类推,填写dp table.具体见注释。

class Solution:
    def getMoneyAmount(self, n: int) -> int:
        #  1-n
        # dp数组: n+1 * n+1
        dp = [[0] * (n+1) for i in range(n+2)]
        # 区间长度 dp[i][i] 就是len=1的情况 结果为0,所以从2-n
        for len in range(2,n+1):
            # 区间起点,区间终点 n-len+1
            for start in range(1,n-len+2):
                # 分割点,第一次猜的数,终点是start + len -1(不包括)
                temp = float('inf')
                for piv in range(start,start+len-1):
                    # 每个分割点所获得最大值,局部最大值,再求此区间的最小值
                    res = piv + max(dp[start][piv-1],dp[piv+1][start+len-1])
                    temp = min(temp,res)
                dp[start][start+len-1] = temp
        return dp[1][n]





第12题:

思路:dp[i]代表以索引为i的数字为结尾的最长递增子序列的长度,遍历所有num[i] > num[j],j属于[0,i)区间,得到max(dp[j]),dp[i] = max(dp[j]) + 1,最后的结果就是max(dp)

class Solution:
    def lengthOfLIS(self, nums) -> int:
        # 动态规划
        # dp[i]代表以索引为i的数字为结尾的最长递增子序列的长度
        dp = [1] * len(nums)
        res = 1
        for i in range(1,len(nums)):
            for j in range(0,i):
                if nums[i] > nums[j]:
                    dp[i] = max(dp[i],dp[j] + 1)
            res = max(res,dp[i])
        return res


第13题:

思路:从矩阵右上角搜索,小于矩阵值则舍去这一列,大于矩阵值则舍去这一行

class Solution:
    def searchMatrix(self, matrix, target: int) -> bool:
        if not matrix:
            return matrix
        # 从矩阵的右上角开始(中等的数,矩阵的左上角和右下角分别是最大的数和最小的数)
        r = len(matrix)
        c = len(matrix[0])
        x,y = 0,c-1
        while x < r and y >= 0:
            if matrix[x][y] == target:
                return True
            # 小于矩阵值,当前列不用搜索了(当列下面的值更大)
            if matrix[x][y] > target:
                y -= 1
            # 大于矩阵值,跳到下一行搜索
            else: x += 1
        return False

第14题:

思路:利用字典存储字典键(数组的值),值存储一个3个元素的列表[c,i,j]分别代表出现的频数、首次出现的位置、最后一次出现的位置。最后遍历字典的值,得到答案

class Solution:
    def findShortestSubArray(self, nums) -> int:
        # 字典存储一个3个元素的列表[c,i,j]分别代表出现的频数、首次出现的位置、最后一次出现的位置
        map = dict()
        for i ,num in enumerate(nums):
            if num in map:
                map[num][0] += 1
                map[num][2] = i
            else:
                map[num] = [1,i,i]
            maxdu = minlen = 0
        for c,i,j in map.values():
            if maxdu < c:
                maxdu = c
                minlen = j-i+1
            elif maxdu == c:
                minlen = min(minlen,j-i+1)
        return minlen





 

第15题:

方法(1):遍历所有城市,对当前城市进行深度优先搜索,看和哪些城市相连通,再对连通城市进行dfs,具体见注释。

class Solution:
    def findCircleNum(self, isConnected) -> int:
        n = len(isConnected)
        # 存储已经访问过的城市
        visted = set()
        # 统计dfs了几次,也就是省份的数量
        count = 0
        def dfs(i):
            for j in range(n):
                # 判断当前城市和哪几个城市连通
                if isConnected[i][j] == 1 and j not in visted:
                    visted.add(j)
                    # 对连通城市再进行dfs
                    dfs(j)
        for i in range(n):
            if i not in visted:
                visted.add(i)
                count += 1
                dfs(i)
        return count

方法(2):并查集,把相连的城市合并为一个连通分量,最后查询有几个不同的连通的连通分量。

# 并查集解法
class UnionSet:
    def __init__(self,n):
        self.parent = [i for i in range(n)]
        self.count = [1 for _ in range(n)]
    def find(self,x):
        # 寻找根节点
        root = x
        while root != self.parent[root]:
            root = self.parent[root]
        # 路径压缩
        while self.parent[x] != root:
            self.parent[self.parent[x]] = root
            x = self.parent[x]
        return root
    def union(self,x,y):
        root_x,root_y = self.find(x),self.find(y)
        if root_x != root_y:
            # 按高度合并
            if self.count[root_x] < self.count[root_y]:
                self.parent[root_x] = root_y
                self.count[root_y] += self.count[root_x]
            else:
                self.parent[root_y] = root_x
                self.count[root_x] += self.count[root_y]
class Solution:
    def findCircleNum(self, isConnected):
        unionSet = UnionSet(len(isConnected))
        for i in range(len(isConnected)):
            for j in range(i+1,len(isConnected[0])):
                if isConnected[i][j] == 1:
                    unionSet.union(i,j)
        ans = set()
        for i in range(len(isConnected)):
            ans.add(unionSet.find(i))
        return len(ans)

第16题:

方法(1):弗洛伊德算法,dp[i][j]表示节点i到节点j的最短路径,穷举所有的节点k,作为i,j的中间节点,看是否对i,j的最短路径最贡献。在求dp数组中第k行的最大值,就是答案。

class Solution:
    def networkDelayTime(self, times, n: int, k: int) -> int:
        # 弗洛伊德算法,初始化dp
        dp = [[float('inf')]*(n+1) for _ in range(n+2)]
        for time in times:
            dp[time[0]][time[1]] = time[2]
        for i in range(1,n+1):
            dp[i][i] = 0

        # 算法主体 尝试所有x,以x为分割点,看看k节点对于从i,j的最短路径有没有贡献
        for x in range(1,n+1):
            for i in range(1,n+1):
                for j in range(1,n+1):
                    dp[i][j] = min(dp[i][j],dp[i][x] + dp[x][j])
        res = 0
        for i in range(1,n+1):
            res = max(dp[k][i],res)
        return res if res < float('inf') else -1

 方法(2):Dijkstra算法,每次选择一个离初始节点最近的点(权值最小)来更新其它节点的权值。为了方便更快的找出离初始节点最近的点,这里采用了优先级队列。

class Solution:
    def networkDelayTime(self, times, n: int, k: int) -> int:
        # Dijkstra
        g = [[] for _ in range(n+1)]
        for time in times:
            g[time[0]].append((time[1],time[2]))
        dist = [float('inf')] * (n+1)
        dist[k] = 0
        q = [(k,0)]
        while q:
            cur,costs = heapq.heappop(q)
            if dist[cur] < costs:
                continue
            for next,next_time in g[cur]:
                if dist[cur] + next_time < dist[next]:
                    dist[next] = dist[cur] + next_time
                    heapq.heappush(q,(next,dist[next]))
        return max(dist[1:]) if max(dist[1:]) < float('inf') else -1

 

第17题:

思路:利用单调队列存储每个窗口可能的最大值,如果单调队列的队头索引i+len>cur,说明nums[i]在以cur为结尾的窗口中是有效的。

class Solution:
    def maxSlidingWindow(self, nums, k: int) :
        n = len(nums)
        if not nums or k == 1 or n == 1:
            return nums
        # 单调递减队列,队列存储着窗口可能的最大值
        queue = []
        for i in range(k):
            # 每次和队尾比,如果当前队尾小说明当前队尾不可能是窗口的最大值,删除
            while queue and nums[i] >= nums[queue[-1]]:
                queue.pop()
            queue.append(i)
        res = [nums[queue[0]]]
        for i in range(k,n):
            while queue and nums[i] >= nums[queue[-1]]:
                queue.pop()
            queue.append(i)
            # 超出窗口范围
            while queue and queue[0] <= i-k:
                queue.pop(0)
            res.append(nums[queue[0]])
        return res

第18题:

思路:和省份城市那题类似,遍历每一个字符串利用dfs把和该字符串相似的字符串全部找出来,再把相似字符串进行dfs,把访问过的字符串加入set集合中,防止重复访问,dfs了几次就有几个数组。

class Solution:
    def numSimilarGroups(self, strs) -> int:
        def isVailed(str1,str2):
            i = j = 0
            while i < len(str1) and j < len(str2):
                if str1[i] != str2[j]:
                    ii,jj = i+1,j+1
                    while str1[ii] == str2[jj]:
                        ii += 1
                        jj += 1
                    str1 = list(str1)
                    temp = str1[i]
                    str1[i] = str1[ii]
                    str1[ii] = temp
                    str1 = ''.join(str1)
                    if str1 != str2:
                        return False
                    return True
                i += 1
                j += 1
        def dfs(s):
            for t in strs:
                if t not in visted and isVailed(s,t):
                    visted.add(t)
                    dfs(t)
        visted = set()
        count = 0
        for s in strs:
            if s not in visted:
                visted.add(s)
                dfs(s)
                count += 1
        return count

第19题:

思路:nums[i][i] 是两个完全平方数之和,如第3行,第3列nums[2][2] = 13 = 2^2 + 3^2.

# 19 蛇形矩阵
# i为你想求的第几行
i = 40
ans = (i-1)*(i-1) + i*i
print(ans)

第20题:

思路:把数字i转化为字符串,遍历字符串寻找字符2

# 20 门牌号
# 计数
count = 0
# n为你想求的门牌号结尾
n = 4040
for i in range(2,n+1):
    s =str(i)
    for j in s:
        if j == '2':
            count += 1
print(count)

第21题:

思路:蛮力法,遍历矩阵,以每个元素作为起点,进行尝试,具体见注释

# 21 三升序列
s = str(input())
# 按行切分
s = s.split()
n = len(s)
m = len(s[0])
# print(n,m)
data = [['']*m for _ in range(n+1)]
# print(data)
# 把输入的字符串转化为矩阵
for i in range(n):
    for j in range(m):
        data[i][j] = s[i][j]
res = 0
# 5个方向
dic = [(-1,1),(0,1),(1,1),(1,0),(1,-1)]
for i in range(n):
    for j in range(m):
        # 以data[i][j]为起点,从左往右包括右上,右,右下、
        # 从上往下包括左下,下,右下一共5中情况,分别遍历
        for (dx,dy) in dic:
            x1,y1 = i+dx,j+dy
            # 单个方向一直搜索
            while 0 <= x1 < n and 0 <= y1 < m:
                x2,y2 = x1+dx,y1+dy
                while 0 <= x2 < n and 0 <= y2 < m:
                    if data[i][j] < data[x1][y1] < data[x2][y2]:
                        res += 1
                    x2 += dx
                    y2 += dy
                x1 += dx
                y1 += dy
print(res)

第22题:

思路:先算小时,再算分钟,具体见注释

# 22 时间判定

a = int(input())
b = int(input())
t = int (input())
 # 几个小时,向下取整
n = t // 60
a += n
# 判定剩余分钟数加起来是否还够一小时
b += t - n*60
if b > 60:
    a += 1
    b -= 60
print(a)
print(b)

第23题:

思路:从头开始,两两比较距离

# 23 字母内部距离
# s为你想求的字符串
s = 'WATJKJDXRGZNXYTW'
res = 0
for i in range(len(s)-1):
    for j in range(i+1,len(s)):
        res += abs(ord(s[i]) - ord(s[j]))
print(res)

第24题:

思路:递归,每一步都有2个台阶或者1个台阶,一直走到39,判断步数是否为偶数

# 24 电影台阶
res = 0
def helper(f,n):
    global res
    if f > 39:
        return
    if f == 39 and n % 2 == 0:
        res += 1
    helper(f+1,n+1)
    helper(f+2,n+1)
helper(0,0)
print(res)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值