leecode

rongyao425 1

s = input().strip()
op = 0
if s[0] == '+':
    s = s[1:]
elif s[0] == '-':
    op = 1
    s = s[1:]


num = int(s)
if op == 1:
    num = -num
if num>pow(2,31)-1:
    print('INT_MAX')
elif num<-pow(2,31):
    print('INT_MIN')
else:
    print(num)

rongyao425 2

l = list(input().split())
# print(l)
p = float(l[0])
M = int(l[1])
lower = int(l[2])
upper = int(l[3])


def calculate_C(a,b):
    up = 1
    lo = 1
    i = 1
    while i<=b:
        up *= a
        a -= 1
        lo *= i
        i += 1
    return up/lo
result = 0
for i in range(lower,upper+1):
    C = calculate_C(M,i)
    p_i = C * pow(p,i)*pow(1-p,M-i)
    result += p_i
print("{:1.2f}".format(result))

rongyao0425 3

s_list = list(map(str,input().strip().split(',')))
# print(s_list)


# 前缀和,从1开始
pre_s = [0 for _ in range(len(s_list) + 1)]
for i in range(len(s_list)):
    pre_s[i+1] = pre_s[i] + len(s_list[i])
# print(pre_s)


n = int(input())



word_list = []
word_count = 0


# 双指针
i = 0
j = 1
while j < len(s_list) +1:
    word_count = pre_s[j] - pre_s[i] + j-i-1
    if word_count > n:
        tmp_list = []
        for k in range(i+1,j):
            tmp_list.append(k)
            
        word_list.append(tmp_list)
        i = j-1
        word_count = 0
    else:
        j += 1


tmp_list = []
for k in range(i+1,j):
    tmp_list.append(k)
word_list.append(tmp_list)
print(word_list)


# 模拟
for k in range(len(word_list)):
    l = word_list[k]
    word_length = pre_s[l[-1]] - pre_s[l[0]-1]
    word_row = ""
    if k == len(word_list)-1:
        for i in range(len(l)):
            word_row += s_list[l[i]-1] + "#"
        tmp = n-len(word_row)
        word_row += "#"*tmp
    elif len(l) == 1:
        tmp = n-word_length
        word_row = s_list[l[0]-1] + tmp*"#"
    elif (n-word_length)%(len(l)-1) != 0:
        tmp = (n-word_length)//(len(l)-1)
        remain = n-word_length - tmp*(len(l)-1)
        for i in range(len(l)):
            if i != len(l)-1:
                word_row += s_list[l[i]-1] + "#"*tmp
                if remain != 0:
                    word_row += "#"
                    remain -= 1
        word_row += s_list[l[i]-1] 
    else:
        tmp = (n-word_length)//(len(l)-1)
        for i in range(len(l)):
            if i != len(l)-1:
                word_row += s_list[l[i]-1] + "#"*tmp
        word_row += s_list[l[i]-1]
    print(word_row)

huawei426 1

import collections
N = int(input().strip())
# 入度
indegree = [0 for _ in range(N+1)]
# 出度节点
nx = collections.defaultdict(list)
for i in range(1,N+1):
    l = list(map(int,input().strip().split()))
    indegree[i] = l[0]
    for j in l[1:]:
        nx[j].append(i)


# 拓扑排序
q = collections.deque()
for i in range(1,N+1):
    if indegree[i] == 0:
        q.append(i)
cnt = 0
node_num = 0
while q :
    res = len(q)
    # 统计初始化次数
    cnt += 1
    for i in range(res):
        node = q.popleft()
        # 统计节点数
        node_num += 1
        for child in nx[node]:
            indegree[child] -= 1
            if indegree[child] == 0:
                q.append(child)
    # 有环
    if node_num > N:
        print(-1)
        break
print(cnt)

huawei426 2

class Node:
    def __init__(self,val,next = None,pre = None):
        self.val = val
        self.next = next
        self.pre = pre


lo,up = map(int,input().strip().split())



# 建立双向链表以及哈希表
hash_table = dict()
id2node = dict()
head = Node(-1)
tail = Node(-1)
tmp = head
used_set = set()
for i in range(lo,up+1):
    node = Node(i)
    hash_table[i] = node
    id2node[node] = i
    node.pre = tmp
    tmp.next = node
    tmp = node
tail.pre = tmp



# 输入操作
op_num = int(input())
for i in range(op_num):
    op_list = list(map(int,input().strip().split()))
    if op_list[0] == 1:
        if up - lo +1 -len(used_set)<op_list[1]:
            continue
        else:
            tmp = head
            j = 0
            while j < op_list[1]:
                tmp = head.next
                used_set.add(tmp)
                j += 1
            head.next = tmp.next
    elif op_list[0] == 2:
        node = hash_table[op_list[1]]
        if node in used_set:
            continue
        else:
            used_set.add(node)
            pre = node.pre
            next = node.next
            node.pre.next = next
            node.next.pre = pre
    elif op_list[0] == 3:
        node = hash_table[op_list[1]]
        if node not in used_set:
            continue
        else:
            used_set.remove(node)
            tail.pre.next = node
            node.next = tail
            tail.pre = node



print(id2node[head.next])

meituan415 贪心

n = int(input())
a_list = list(map(int,input().strip().split()))
b_list = list(map(int,input().strip().split()))
c_list = list(map(int,input().strip().split()))


d_list = [[a_list[i],b_list[i],c_list[i]] for i in range(len(a_list))]


# 外
tao1 = sorted(d_list,key = lambda x:x[0])
# 内
tao2 = sorted(d_list,key = lambda x:x[1])


# 二分搜索
def binary_search(l_list,target):
    l = 0
    r = len(l_list)
    while l<r:
        mid = (l+r)//2
        if l_list[mid][0] > target:
            r = mid
        elif l_list[mid][0] <= target:
            l = mid + 1
        elif l == 0 and r ==0 and mid == 0:
            return -1


    return l-1


# 每次找满足条件的外最大的
size_ = float('inf')
cost = 0
per = 0
pre_idx = 0
while True:
    idx= binary_search(tao1,size_)
    if idx == -1:
        break 
    if size_ != float('inf'):
        tao2[pre_idx][1] -= tao1[idx][0]
    pre_idx = idx
    size_ = tao1[idx][1]
    per = tao1[idx][2]


for a,b,c in tao2:
    cost += b*c



print(cost)

meituan415 模拟

n = int(input())
l = list(map(int,input().split()))
hash_table = dict()
for i in range(n+1):
    hash_table[i] = 0
for i in l:
    hash_table[i] += 1
for key in hash_table:
    if hash_table[key] > 1 and key<n:
        hash_table[key] -= 1
        hash_table[key+1] += 1
for i in range(n+1):
    if hash_table[i] == 0:
        print(i)
        break

rongyao422 bfs

import collections
l = list(map(int,input().strip().split()))
q = collections.deque()
for i in range(0,(len(l)+1)//2):
    q.append(i)


n = len(q)
node = 0
path = 1
flag = True


# bfs
while q:
    idx = q.popleft()
    node += 1
    if l[idx] + idx == len(l)-1:
        print(path + 1)
        flag =False
        break
    elif l[idx] +idx>len(l):
        pass
    else:
        q.append(idx+l[idx])
    if node == n:
        path += 1
        node = 0
        n = len(q)
if flag:
    print(-1)

rongyao0422 3

n,m = map(int,input().strip().split())
height = [[0]*m for _ in range(n)]
for i in range(n):
    height[i] = list(map(int,input().strip().split()))
x,y,z,w = map(int,input().strip().split())


dp = {}
dirs = [[1,0],[-1,0],[0,1],[0,-1]]
# dp + dfs(dp的顺序)
def dfs(i,j):
    if i==z and j == w:
        return 1
    # 记忆化搜索
    if (i,j) in dp:
        return dp[(i,j)]
    cur = 0
    for nx,ny in dirs:
        if nx+i>=n or ny+j>=m or nx+i<0 or ny+j<0 or height[i][j]>=height[i+nx][j+ny]:
            continue
        cur += dfs(nx+i,ny+j)
    dp[(i,j)] = cur
    return cur
print(dfs(x,y))

huawei0506 3

import collections
n = int(input().strip())
k = int(input().strip())
k_list = list(map(int,input().strip().split()))
k_list = [(k_list[i],k_list[i+1]) for i in range(len(k_list))if i %2 == 0]
girl_boy = list(map(int,input().strip().split()))
girl = girl_boy[:2]
boy = girl_boy[2:]
map_ = []
for i in range(n):
    line = list(input().strip().split())
    map_.append(line)


q = collections.deque()


# 添加时间维度,判断第几层,适用于bfs中需要判断层次的题目
q.append((boy[0],boy[1],0))
flag = True
while len(q) != 0:
    if flag == False:
        break
    tmpx,tmpy,time = q.popleft()
    for pulsx,plusy in [0,0],[0,1],[1,0],[-1,0],[0,-1]:
        x = tmpx+pulsx
        y = tmpy+plusy
        if x >=n or y >=n or x < 0 or y < 0:
            continue
        elif map_[x][y][(time+1)%3] == '1' or (x,y) in k_list:
            continue
        else:
            if [x,y] == girl:
                flag =False
                break
            else:
                q.append((x,y,time+1))
    
    
print(time+1)

leecode 121

# 交易一次,套用交易k次的板子
class Solution:
    def maxProfit(self, prices):

        # k笔交易
        # 2*k个变量
        k = 1
        l = prices
        buy_list = [-l[0]]*k
        sell_list = [0]*k
        if len(l) == 1:
            return 0
        else:
            for i in range(1,len(l)):
                for j in range(k):
                    if j == 0:
                        buy_list[j] = max(buy_list[j],-l[i])
                        sell_list[j] = max(sell_list[j],buy_list[j]+l[i])
                    else:
                        buy_list[j] = max(buy_list[j],sell_list[j-1]-l[i])
                        sell_list[j] = max(sell_list[j],buy_list[j]+l[i])
            return max(sell_list)
if __name__ == "__main__":
    prices = [1,4,2]
    solution = Solution()
    ans = solution.maxProfit(prices)
    print(ans)

leecode122

# 任意交易,连个变量,类似于k次交易的板子,只不过对第一次交易不用特殊处理,因为
# 这个板子用两个变量存储了多次交易的收益,没有数组就不存在溢出的风险
#dp1 dp0分别代表买了股票和卖了股票
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        l = prices
        dp0 = -l[0]
        dp1 = 0
        if len(l) == 1:
            return 0
        for i in range(1,len(l)):
            dp0,dp1= max(dp0,dp1-l[i]),max(dp0+l[i],dp1)
        return dp1

leecode123

# 两笔交易
# 3 3 5 0 0 3 1 4
# 6
# 四个转移变量
# 套用k次交易的板子
class Solution:
    def maxProfit(self, prices):

        # k笔交易
        # 2*k个变量
        k = 2
        l = prices
        buy_list = [-l[0]]*k
        sell_list = [0]*k
        if len(l) == 1:
            return 0
        else:
            for i in range(1,len(l)):
                for j in range(k):
                    if j == 0:
                        buy_list[j] = max(buy_list[j],-l[i])
                        sell_list[j] = max(sell_list[j],buy_list[j]+l[i])
                    else:
                        buy_list[j] = max(buy_list[j],sell_list[j-1]-l[i])
                        sell_list[j] = max(sell_list[j],buy_list[j]+l[i])
            return max(sell_list)

leecode188

# k笔交易
# 2*k个变量
# 注意临界值的处理 j == 0(第一次交易),用了数组来存储,
# k次交易的收益,存在溢出风险
class Solution:
    def maxProfit(self, k: int, prices: List[int]) -> int:
        # k笔交易
        # 2*k个变量
        l = prices
        buy_list = [-l[0]]*k
        sell_list = [0]*k
        if len(l) == 1:
            return 0
        else:
            for i in range(1,len(l)):
                for j in range(k):
                    if j == 0:
                        buy_list[j] = max(buy_list[j],-l[i])
                        sell_list[j] = max(sell_list[j],buy_list[j]+l[i])
                    else:
                        buy_list[j] = max(buy_list[j],sell_list[j-1]-l[i])
                        sell_list[j] = max(sell_list[j],buy_list[j]+l[i])
            return max(sell_list)

leecode309

# 任意交易且包含冷冻期,套用任意交易的板子
# dp0 dp1分别代表买了股票和卖了股票的收入,,dp2存储t-2时刻的卖出股票的收入
class Solution:
    def maxProfit(self, prices):
        l = prices
        dp0 = -l[0]
        dp1 = 0
        dp2 = 0
        if len(l) == 1:
            return 0
        for i in range(1,len(l)):
            dp0 = max(dp0,-l[i] +(dp2 if i>1 else 0))
            # 要注意dp2的位置
            dp2 = dp1
            dp1 = max(dp1,dp0+l[i])
        
        return dp1

leecode 741

#和任意次数交易一样,只需要减去手续费
class Solution:
    def maxProfit(self, prices, fee) -> int:
        l = prices
        dp0 = -l[0]
        dp1 = 0
        if len(l) == 1:
            return 0
        for i in range(1,len(l)):
            dp0,dp1= max(dp0,dp1-l[i]),max(dp0+l[i]-fee,dp1)
        return dp1

快排求top-k

import random
class Solution:
    def findKthLargest(self, nums, k):
        l = 0
        r = len(nums) - 1
        target =  len(nums) - k
        while True:
            piviotIndex = self.partion(l,r,nums)
            if piviotIndex == target:
                return nums[piviotIndex]
            elif piviotIndex > target:
                r = piviotIndex - 1
            else:
                l = piviotIndex + 1
    def partion(self,l,r,nums):
        randomindex = random.randint(l,r)
        nums[l],nums[randomindex] = nums[randomindex],nums[l]
        piviot = nums[l]
        piviot_index = l
        # 不能丢,否则容易超时
        l =  l + 1
        while True:
            while l<=r and nums[l] < piviot:
                l += 1
            while l<=r and nums[r] > piviot:
                r -= 1
            if l >= r:
                break
            nums[l],nums[r] = nums[r],nums[l]
            # 不能丢,否则容易超时,特别是没有走上面两个循环的时候
            l += 1
            r -= 1
        nums[r],nums[piviot_index] = nums[piviot_index],nums[r]
        return  r


if __name__ == "__main__":
    solution = Solution()
    nums = [3,2,1,5,6,4]
    k = 2
    ans = solution.findKthLargest(nums,k)
    print(ans)

取两个或两个以上的数字

# 动态规划
"""
首先,一个长度为n的数组最多能取出n-1个单调序列(如果整个数组是单调递增或者单调递减的话)。所以,我们可以从长度为2的序列开始,一直枚举到长度为n的序列,对于每个长度,统计可以取出的单调序列的个数即可。

具体实现可以用一个二维数组dp来辅助计算,其中dp[i][j]表示以第i个数结尾,长度为j的单调递增子序列的个数。转移方程为:

dp[i][j] = dp[k][j-1] + 1,其中0 <= k < i,且a[k] < a[i]

这个方程的含义是,以第i个数结尾,长度为j的单调递增子序列的个数,等于以前面任意一个比它小的数k结尾,长度为j-1的单调递增子序列的个数,再加上自己构成的长度为2的序列。这样,当枚举到长度为n的序列时,可以把所有dp[n][j]累加起来,得到所有长度为j的单调递增子序列的个数。同理,可以再用一个dp数组来计算单调递减子序列的个数,最后把两个结果相加即可。
"""
### 仅仅实现递增的部分
# 注意可以实现用一个数组存储离l[k]最近的比它小的数,降低时间复杂度
def find_latest_min(l,base_index,find_index):
    for i in range(find_index,-1,-1):
        if l[i] < l[base_index]:
            return i
    return -1

l = list(map(int,input().strip().split()))
latest_min = [0] * len(l)
for i in range(1,len(l)):
    if l[i]>l[i-1]:
        latest_min[i] = i - 1
    elif l[i]>l[latest_min[i-1]]:
        latest_min[i] = latest_min[i-1]
    else:
        latest_min[i] = find_latest_min(l,i,latest_min[i-1])

# 动态规划,以i结尾的递增序列
dp = [1]*len(l)
for i in range(1,len(l)):
    if latest_min[i] != -1:
        dp[i] = dp[latest_min[i]] + 1
    else:
        dp[i] = 1

# print(dp)


# 求和
sum_ = 0
for i in range(len(dp)):
    if dp[i]>=2:
        sum_ += dp[i]-2+1
print(sum_)

 


编辑距离

"""
horse
ros
3
"""


s1 = input().strip()
s2 = input().strip()
dp = [[0]*(len(s2)+1) for _ in range(len(s1)+1)]


for i in range(len(s1)+1):
    for j in range(len(s2)+1):
        if i == 0 or j == 0:
            if i== 0:
                dp[0][j] = j
            else:
                dp[i][0] = i
        elif s1[i-1] == s2[j-1]:
            dp[i][j] = dp[i-1][j-1]
        else:
            # dp[i][j-1]是在s1[i-1]后添加一个字符s1[j-1],dp[i-1][j]是删除s1[i-1],dp[i-1][j-1]是修改s1[i-1]为s2[j-1]
            dp[i][j] = min(dp[i][j-1],dp[i-1][j],dp[i-1][j-1]) + 1
print(dp[len(s1)][len(s2)])

leecode 295数据流的中位数

import heapq
class MedianFinder:


    def __init__(self):
        self.que_min = []
        self.que_max = []




    def addNum(self, num: int) -> None:
        if not self.que_max or num<=-self.que_max[0]:
            heapq.heappush(self.que_max,-num)
            if len(self.que_min) + 1 <len(self.que_max):
                heapq.heappush(self.que_min,-heapq.heappop(self.que_max))
        else:
            heapq.heappush(self.que_min,num)
            if len(self.que_min)>len(self.que_max):
                heapq.heappush(self.que_max,-heapq.heappop(self.que_min))


        
    def findMedian(self) -> float:
        if len(self.que_max)>len(self.que_min):
            return -self.que_max[0]
        else:
            return (-self.que_max[0]+self.que_min[0])/2

翻转链表

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
# 原地翻转(有递归版本和迭代版本)
# 维护pre cur 和 next,让cur的next指针域指向前面
class Solution:
    def reverseList(self, head):
        cur = head
        if cur!=None:
            next = cur.next
        else:
            return None
        pre = None
        while cur!=None:
            cur.next = pre
            pre = cur
            cur = next
            if next!=None:
                next = next.next
        return pre
            


# 头插法(有原地和需要空间版本。原地版本让后面节点不断插到前面节点,空间版本如同构建链表一样,头插法)

无重复的最长子串

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        start = 0
        end = 0
        max_num = 0
        # 存下目前子串中所有字符
        hash_set = set()
        while end<len(s):
            if s[end] not in hash_set:
                hash_set.add(s[end])
                max_num = max(max_num,end-start+1)
                end += 1
            else:
                while start < len(s) and s[start]!=s[end]:
                    # 移除不在子串中的字符
                    hash_set.remove(s[start])
                    start += 1
                # 加上相等的这个
                hash_set.add(s[start])
                start += 1
                max_num = max(end-start+1,max_num)
                end += 1
        return max_num
            


if __name__ == "__main__":
    solution = Solution()
    s = "tmmzuxt"
    ans = solution.lengthOfLongestSubstring(s)
    print(ans)

二叉树的最大直径

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def diameterOfBinaryTree(self, root: TreeNode) -> int:
        # 注意+1和的细小操作
        self.ans = 0
        def dfs(node):
            if node == None:
                return 0
            L = dfs(node.left)
            R = dfs(node.right)
            self.ans = max(self.ans,L+R)
            return max(L,R) + 1
        dfs(root) 
        return self.ans

柱状图中最大的矩形

class Solution:
    def largestRectangleArea(self, heights):
        stack = []
        ans = 0
        heights = [0] + heights + [0]
        for i in range(len(heights)):
            while stack and heights[stack[-1]]>heights[i]:
                tmp = stack.pop()
                ans = max(ans,(i-stack[-1]-1)*heights[tmp])
            stack.append(i)
        return ans


if __name__ == "__main__":
    l =  [2,1,5,6,2,3]
    solution = Solution()
    ans = solution.largestRectangleArea(l)
    print(ans)

meituan0513 第三题

n = int(input().strip())
l = list(map(int,input().strip().split()))
cnt = n//2
i,j = 0,0
if n % 2 == 0 :
    i = n//2
    j = n//2+1
else:
    i = n//2
    j = n//2+2
dic = {l[i]:i for i in range(n)}
while i > 0:
    if dic[i]<dic[j]:
        cnt -= 1
    if dic[i-1]<dic[i] and dic[j+1]>dic[j]:
        i -= 1
        j += 1
    else:
        break
print(cnt)

huawei 0510 3 迪杰斯特拉

关键点:#优先队列储存下一步可选路径

# 路径长度数组

#迪杰斯特拉算法,本题加了一个自身节点的消耗,但是基本思想都一样

#最长的路径为源节点到终结点点路径

import heapq
from collections import defaultdict
n = int(input())
m = int(input())
systime = defaultdict(int)
nxs = defaultdict(list)
for _ in range(m):
    s,d,t = map(int,input().strip().split())
    if s == d:
        systime[s] = t
    else:
        nxs[s].append((d,t))
start = int(input())
h = []
#储存下一步可选路径
heapq.heappush(h,(0,start))
dis = [float('inf') for _ in range(n+1)]
# 路径长度数组
dis[start] = 0


# 迪杰斯特拉
while h:
    time,node = heapq.heappop(h)
    for nx,nxtime in nxs[node]:
        if dis[nx] > time +systime[nx]+nxtime:
            heapq.heappush(h,(time +systime[nx]+nxtime,nx))
            dis[nx] = time +systime[nx]+nxtime


# 最长的路径为源节点到终结点点路径
cnt = 0
res = 0
for d in dis:
    if d != float('inf'):
        cnt += 1
        res = max(res,d)
print(cnt,res)

联通子图个数 使用并查集后,根节点的数量为联通子图的个数

class UnionFind:
    def __init__(self):
        self.pair = list(range(50001))
    def find(self,x):
        if x != self.pair[x]:
            x = self.find(self.pair[x])
        return self.pair[x]
    def union(self,x,y):
        px,py = self.find(x),self.find(y)
        self.pair[py] = px 
              
class Solution:
    def countComponents(self, n, edges):
        uf = UnionFind()
        for e in edges:
            uf.union(e[0],e[1])


        # 根节点的数量为联通子图的个数
        seen = set()
        for i in range(n):
            pa = uf.find(i)
            seen.add(pa)
        return len(seen)

二叉树转化为先序链表

class Solution:
    def flatten(self, root: TreeNode) -> None:
        curr = root
        while curr:
            if curr.left:
                predecessor = nxt = curr.left
                while predecessor.right:
                    predecessor = predecessor.right
                predecessor.right = curr.right
                curr.left = None
                curr.right = nxt
            curr = curr.right



"""
注意到前序遍历访问各节点的顺序是根节点、左子树、右子树。如果一个节点的左子节点为空,则该节点不需要进行展开操作。如果一个节点的左子节点
不为空,则该节点的左子树中的最后一个节点被访问之后,该节点的右子节点被访问。该节点的左子树中最后一个被访问的节点是左子树中的最右边的节
点,也是该节点的前驱节点。因此,问题转化成寻找当前节点的前驱节点。


具体做法是,对于当前节点,如果其左子节点不为空,则在其左子树中找到最右边的节点,作为前驱节点,将当前节点的右子节点赋给前驱节点的右子节
点,然后将当前节点的左子节点赋给当前节点的右子节点,并将当前节点的左子节点设为空。对当前节点处理结束后,继续处理链表中的下一个节点,直
到所有节点都处理结束。
"""

leecode 377 排列数 动态规划

固定背包,遍历元素是排列

固定元素,遍历背包是组合

class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        dp = [1] + [0] * target

        for i in range(1,target+1):
            for num in nums:
                if num <= i:
                    dp[i] += dp[i-num]
        return dp[target]

快速排序

def qsort(nums,l,r):
    if l >= r:
        return
    low = l
    high = r
    key = nums[low]
    while l < r:
        while l<r and nums[r]>key:
            r -= 1
        nums[l] = nums[r]
        while l< r and nums[l]<= key:
            l += 1
        nums[r] = nums[l]
    nums[l] = key
    qsort(nums,low,l-1)
    qsort(nums,l+1,high)


nums = [5,3,6,4,1,2,8,7]
qsort(nums,0,len(nums)-1)
print(nums)

归并排序

自顶向下 非原地

def mergesort(seq):
    if len(seq)<=1:
        return seq
    mid = len(seq)//2
    left = mergesort(seq[:mid])
    right = mergesort(seq[mid:])
    return merge(left,right)
def merge(left,right):
    result = []
    i = 0
    j = 0
    while i < len(left) and j < len(right):
        if left[i]<=right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result.extend(left[i:])
    result.extend(right[j:])
    return result


seq = [5,3,0,6,1,4]
print(seq)
result = mergesort(seq)
print(result)

快排 自地底部向上 原地

"""
在 merge_sort 函数中,我们使用 size 变量表示归并的子数组大小。首先将 size 初始化为 1,然后循环进行归并操作,每次将 left 指针从 0 开始,每次循环时将 left 指针向右移动 size 步,同时计算 mid 和 right 指针的位置。然后调用 merge 函数对两个有序子数组进行归并。


在 merge 函数中,我们使用两个指针 i 和 j 分别指向两个子数组的开头,并比较两个子数组中的元素大小。如果右侧子数组中的元素更小,则将它插入到左侧子数组中。为了实现原地排序,我们需要将左侧子数组中大于当前元素的所有元素向右移动一个位置,然后再将当前元素插入到相应的位置。


这样,我们就可以实现原地归并排序。
"""


def merge_sort(arr):
    n = len(arr)
    size = 1
    while size < n:
        left = 0
        while left < n:
            mid = left + size - 1
            if mid >= n - 1:
                break
            right = min(mid + size, n - 1)
            merge(arr, left, mid, right)
            left = right + 1
        size *= 2



def merge(arr, left, mid, right):
    i = left
    j = mid + 1
    while i <= mid and j <= right:
        if arr[i] > arr[j]:
            temp = arr[j]
            for k in range(j, i, -1):
                arr[k] = arr[k - 1]
            arr[i] = temp
            j += 1
            mid += 1
        i += 1
    return arr


seq = [5,3,0,6,1,4]
print(seq)
merge_sort(seq)
print(seq)

leecode138 复制带有随机指针的链表 之间复杂度为O(n),空间复杂度为O(1)(不算返回的空间),巧妙的思路

class Solution(object):
    def copyRandomList(self, head):
        if head == None:
            return None
        p = head
        # 第一步,在每个原节点后面创建一个新节点
        # 1->1'->2->2'->3->3'
        while p != None:
            tmp = Node(p.val,None,None)
            tmp.next = p.next
            p.next = tmp
            p  = tmp.next
        # 第二步,设置新节点的随机节点
        p = head
        while p != None:
            if p.random:
                p.next.random = p.random.next
            p = p.next.next
        # 第三步,将两个链表分离
        p = head
        dummy = Node(-1,None,None)
        cur = dummy
        while p:
            cur.next = p.next
            cur = cur.next
            p.next = cur.next
            p = p.next
        return dummy.next

leecode75 颜色分类 双指针

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        n = len(nums)
        p0,p1 = 0,0
        for i in range(n):
            if nums[i] == 1:
                nums[i],nums[p1] = nums[p1],nums[i]
                p1 += 1
            elif nums[i] == 0:
                nums[i],nums[p0] = nums[p0],nums[i]
                if p0 < p1:
                    nums[i],nums[p1] = nums[p1],nums[i]
                p0 += 1
                p1 += 1

特别的,还有方法一(两次遍历)和方法三(一次遍历)

leecode23 合并k个有序链表,用最小堆,存k个元素,弹出一个节点后,存下该节点的next,分析时间复杂度

import heapq
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        l = []
        for i in range(len(lists)):
            heapq.heappush(lists[i][0])
        x = ListNode(-1)
        cur = x
        while l:
            tmp = heapq.heappop(l)
            cur.next = tmp
            cur = cur.next
            if tmp.next != None:
                heapq.heappush(tmp.next)
        return x.next

leecode238 除自身以外的数的成绩 优化空间后的前缀积和后缀积 只需要O(1)的空间,不算返回的空格

class Solution:
    def productExceptSelf(self, nums: List[int]) -> List[int]:
        length = len(nums)
        answer = [0]*length
        
        # answer[i] 表示索引 i 左侧所有元素的乘积
        # 因为索引为 '0' 的元素左侧没有元素, 所以 answer[0] = 1
        answer[0] = 1
        for i in range(1, length):
            answer[i] = nums[i - 1] * answer[i - 1]
        
        # R 为右侧所有元素的乘积
        # 刚开始右边没有元素,所以 R = 1
        R = 1;
        for i in reversed(range(length)):
            # 对于索引 i,左边的乘积为 answer[i],右边的乘积为 R
            answer[i] = answer[i] * R
            # R 需要包含右边所有的乘积,所以计算下一个结果时需要将当前值乘到 R 上
            R *= nums[i]
        
        return answer

offer39 数组中出现次数超过一半的数字,投票法

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        count = 0
        candidate = None
        for i in range(len(nums)):
            if count == 0:
                candidate = nums[i]
            if candidate == nums[i]:
                count += 1
            else:
                count -= 1
        return candidate

leecode1287 有序数组中出现次数超过25%的数字,遍历(0,n,n//4+1)中有限的点,二分查找左右边界,区间长度大于25%的那个就是返回值,时间复杂度只要O(logn)。也可以顺序遍历,但是时间复杂度为O(n)

class Solution:
    def findSpecialInteger(self, arr: List[int]) -> int:
        n = len(arr)
        span = n//4 + 1
        for i in range(0,n,span):
            l = self.binary_left(arr,arr[i])
            r = self.binary_right(arr,arr[i])
            if r - l + 1>= span:
                return arr[i]
        return -1


    def binary_left(self,nums,target):
        l = 0
        r = len(nums)
        while l < r:
            mid = (l+r)//2
            if nums[mid] == target:
                r = mid
            elif nums[mid] > target:
                r = mid
            else:
                l = mid + 1
        return r


    def binary_right(self,nums,target):
        l = 0
        r = len(nums)
        while l < r:
            mid = (l+r)//2
            if nums[mid] == target:
                l = mid+1
            elif nums[mid] > target:
                r = mid
            else:
                l = mid + 1
        return l-1

leecode15 三数之和,先排序,后双重遍历(遍历第二个数和第三个数是同时开始的),但要注意为了避免重复,每次都要判断上次遍历的数和本次是否相等

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)
        nums.sort()
        ans = list()
        
        # 枚举 a
        for first in range(n):
            # 需要和上一次枚举的数不相同
            if first > 0 and nums[first] == nums[first - 1]:
                continue
            # c 对应的指针初始指向数组的最右端
            third = n - 1
            target = -nums[first]
            # 枚举 b
            for second in range(first + 1, n):
                # 需要和上一次枚举的数不相同
                if second > first + 1 and nums[second] == nums[second - 1]:
                    continue
                # 需要保证 b 的指针在 c 的指针的左侧
                while second < third and nums[second] + nums[third] > target:
                    third -= 1
                # 如果指针重合,随着 b 后续的增加
                # 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
                if second == third:
                    break
                if nums[second] + nums[third] == target:
                    ans.append([nums[first], nums[second], nums[third]])
        
        return ans

leecode153,查找旋转数组的最小值,二分法。注意比较对象、边界和停止条件和普通二分不一样,r = len(nums)-1,和nums[r]比,然后l每次在mid基础上加1,因为结束后要获得最小的数,恰好是比较对象nums[r]后面一个,因此要每次l = mid + 1,最后返回nums[l]。(如果需要结束后获得最大值,则返回nums[l-1]

class Solution:
    def findMin(self, nums):    
        l,r = 0,len(nums)-1
        while l < r:
            mid = (l+r)//2
            if nums[mid]>nums[r]:
                l = mid + 1
            elif nums[mid] < nums[r]:
                r = mid
            else:
                l = mid + 1
            
        return nums[l]#或者nums[r]
    


if __name__ == "__main__":
    solution = Solution()
    nums = [3,4,5,1,2]
    ans = solution.findMin(nums)
    print(ans)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值