左神算法课程代码总结

第一章 复杂度与简单排序算法

三种简单排序

1. 冒泡排序

从左到右两两比较并交换,把最大的交换到最后一个位置

从最后一个位置开始填坑

def bubbleSort(arr,n):
    if len(arr) <2:
        return arr
    for j in range(n-1, 0, -1):
        for i in range(j):
            if arr[i] > arr[i+1]:
                arr[i], arr[i+1] = arr[i+1],arr[i] 
    return arr
n = int(input())    
nums = list(map(int, input().split()))
res = bubbleSort(nums, n)
res = [str(num) for num in res]
print(' '.join(res))
2. 选择排序

从第一个位置开始填坑

每次选择最小的放到第i个位置

def select(n, nums):
    if n < 2:
        return nums
    for i in range(0, n-1):
        minIndex = i
        for j in range(i+1, n):
            if nums[j] < nums[minIndex]:
                minIndex = j
        nums[i], nums[minIndex] = nums[minIndex], nums[i] 
    return nums
n = int(input())
nums = list(map(int, input().split()))
res = select(n, nums)
#res = [str(num) for num in res]
#print(' '.join(res))
print(*res)
3. 插入排序

假设前面 i - 1 个数已经有序,将第 i 个数通过交换的方式插入到前面的正确位置,使得前 i 个数都有序的。

def insertSort(n, arr):
    if n < 2:
        return arr
    for i in range(1,n):
        for j in range(i, 0, -1):
            if arr[j-1] > arr[j]: #凡是大的都换到后面;两两交换
                arr[j-1], arr[j] = arr[j], arr[j-1]
            #else:
                #break 遇到第一个<=当前的就可提前结束循环,因为前面有序,都比他小
    return arr
n = int(input())
nums = list(map(int, input().split()))
res = insertSort(n, nums)
res = [str(num) for num in nums]
print(' '.join(res))

二分查找

4. 二分查找某数

在有序数组中找到目标值 k 的索引,若不存在则返回 -1,存在多个则返回最小的索引

相当于找到第一个比k小的数, 然后加一

def search(n, k, nums):
    i, j = 0, n - 1
    while i <= j:
        m = i + ((j - i) >> 1)  #注意这里不能少了括号,+比>>的优先级高 
        if nums[m] >= k: j = m - 1 #只要比目标大就要继续向左缩小范围
        else: i = m + 1
    index = j + 1
    return index if nums[index] == k else -1

n, k = list(map(int, input().split())) # n, k= [int(i) for i in input().split]
nums = list(map(int, input().split()))
print(search(n, k, nums))
5. 查找某个位置

你需要输入一个n,一个数k,然后输入一个长度为n个大小的数组arr,然后你需要在arr上找满足>=K的最左位置,并且输出这个位置,如果不存在这个位置就输出-1。

示例1

输入

5 1
0 0 2 4 6

输出

2

思路:同样是找到第一个比k小的数, 然后加一,要比目标大就要继续向左缩小范围

def search(n, k, nums):
    if nums[n-1] < k: return -1 
    i, j = 0, n - 1
    while i <= j:
        m = i + ((j - i) >> 1)  
        if nums[m] >= k: j = m - 1
        else: i = m + 1
    index = j + 1
    return index

n, k = list(map(int, input().split())) # n, k= [int(i) for i in input().split]
nums = list(map(int, input().split()))
print(search(n, k, nums))
6. 局部最小值问题

定义局部最小的概念。arr长度为1时,arr[0]是局部最小。arr的长度为N(N>1)时,如果arr[0] < arr[1],那么arr[0]是局部最小;
如果arr[N-1]<arr[N-2],那么arr[N-1]是局部最小;如果0<i<N-1,既有arr[i] < arr[i-1],又有arr[i] < arr[i + 1],那么arr[i]
是局部最小。给定无序数组arr,已知arr中任意两个相邻的数都不相等,只需要返回arr中任意一个局部最小出现的位置即可,如果不存在这个位置就输出-1。

方法一:二分查找

def binarySearch(n, nums):
    if n < 2: return 0
    i, j = 0, n-1
    if nums[i] < nums[i+1]: return 0
    if nums[j] < nums[j-1]: return j
    while i <= j:
        m = i + ((j - i) >> 1)
        if nums[m] < nums[m-1] and nums[m] < nums[m+1]: return m
        elif nums[m] < nums[m+1]: j = m - 1
        else: i = m + 1 # nums[m] < nums[m-1]
    return -1
n = int(input())
nums = list(map(int, input().split()))
res = binarySearch(n, nums)
print(res)

一道复杂度很低用异或运算解决的题

7. 一个数出现奇数次

一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到这一个数?

方法一:利用异或

n = int(input())
nums = list(map(int, input().split()))
eor = 0
for num in nums:
    eor ^= num
print(eor)

第二章 O(N logN)的排序

归并排序

1. 归并排序
  1. 数组归并排序
def process(arr, L, R):
    if L == R:
        return
    mid = L + ((R - L) >> 1)
    process(arr, L, mid)
    process(arr, mid + 1, R)
    merge(arr, L, mid, R)
    
def merge(arr, L, mid, R):
    tmp = []
    p1, p2 = L, mid + 1
    while p1 <= mid and p2 <= R:
        if arr[p1] <= arr[p2]:
            tmp.append(arr[p1])
            p1 += 1
        else:
            tmp.append(arr[p2])
            p2 += 1
    while p1 <= mid:
        tmp.append(arr[p1])
        p1 += 1
    while p2 <= R:
        tmp.append(arr[p2])
        p2 += 1
    arr[L:R+1] = tmp  #注意这里直接return tmp是不对的,因为只用改变L到R+1,不能把arr都改了

n = int(input())
arr = list(map(int, input().split()))
process(arr, 0, n - 1)
print(*arr)
  1. 单链表的归并排序
class Solution:
    def sortInList(self , head: ListNode) -> ListNode:
        if not head or not head.next: return head #空节点或者节点为一,什么都不用做,返回
        slow, fast = head, head.next
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
        mid = slow.next
        slow.next = None
        left = self.sortInList(head)
        right = self.sortInList(mid)
        
        dummy = cur = ListNode(0)
        while left and right:
            if left.val <= right.val:
                cur.next = left
                left = left.next
            else:
                cur.next = right
                right = right.next
            cur = cur.next
        cur.next = left if left else right
        return dummy.next

堆排序

2. 堆排序

1)建堆;2)交换数据;3)向下调整。

#迭代写法二:左神
def heapify(arr, n, i):  #heapify就是不断地在两个孩子中找出最大的那个,然后与父节点交换
    left = i * 2 + 1
    while left < n:
        largest = left + 1 if left + 1 < n and arr[left+1] > arr[left] else left
        largest = i if arr[i] > arr[largest] else largest
        if largest == i:
            break
        arr[i], arr[largest] = arr[largest], arr[i]
        i = largest
        left = 2 * i + 1
           
def heapsort(arr):
    n = len(arr)
    #先建立大根堆
    for i in range(n-1, -1, -1):
        heapify(arr, n, i)  #自底向下遍历,看所有子树的根节点能否下沉
    
    for i in range(n-1, 0, -1):
        arr[0], arr[i] = arr[i], arr[0]  #arr[0] 是最大的,不断地不最大的换到末尾,然后长度减一
        heapify(arr, i, 0) #将换上来的数做heapify,往下沉,以变回最大堆
        
n = int(input())
nums = list(map(int, input().split()))
heapsort(nums)
print(*nums)

补充1:

heapify写法

#迭代写法:mycode
def heapify(arr, n, i):
    left = i * 2 + 1
    right = i * 2 + 2
    while left < n:
        large = right if right < n and arr[left] < arr[right] else left
        if arr[i] >= arr[large]:
            break
        else:
            arr[i], arr[large] = arr[large], arr[i]
            i = large
            left = i * 2 + 1
            right = i * 2 + 2
#递归写法:
def heapify(arr, n, i):
    left = 2 * i + 1
    right = 2 * i + 2
    largest = i
    
    if left < n and arr[left] > arr[i]:
        largest = left
    if right < n and arr[right] > arr[largest]:
        largest = right
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]
        
        heapify(arr, n, largest)

补充2:

用heapInsert的方法建堆

def heapsort(arr):
    n = len(arr)
    arr_heap = []
    for num in arr:
        heapInsert(arr_heap, num)
    for i in range(n-1, 0, -1):
        arr_heap[0], arr_heap[i] = arr_heap[i], arr_heap[0]
        heapify(arr_heap, i, 0) #将换上来的数做heapify,往下沉,以变回最大堆
    return arr_heap
        
def heapInsert(arr, num):
    i = len(arr)
    arr.append(num)
    parent = (i - 1) >> 1  #不断地与父节点比较,大于父节点则交换
    while parent >= 0:
        if arr[parent] < arr[i]:
            arr[parent], arr[i] = arr[i], arr[parent]
            i = parent
            parent = (i - 1) >> 1
        else: break
            
n = int(input())
nums = list(map(int, input().split()))
nums = heapsort(nums)
print(*nums)
3. 荷兰国旗问题

牛牛今天带来了一排气球,气球有n个,然后每一个气球里面都包含一个数字,牛牛是一个善于思考的人,于是他就想到了一个问题,
牛牛随便给你一个值K,这个值在这些气球中不一定存在,聪明的你需要把气球中包含的数字是小于K的放到这排气球的左边,大于K的放到气球的右边,
等于K的放到这排气球的中间,最终返回一个整数数组,其中只有两个值,分别是气球中包含的数字等于K的部分的左右两个下标值,如果气球中没有K这个数字就输出-1,-1。

def helper(arr, target):
    less = -1
    more = len(arr)
    index = 0
    while index < more:
        if arr[index] < target:
            less += 1
            arr[index], arr[less] = arr[less], arr[index]
            index += 1
        elif arr[index] > target:
            more -= 1
            arr[index], arr[more] = arr[more], arr[index]
        else:
            index += 1
    
    return [-1, -1] if less + 1 > more - 1 else [less + 1, more - 1]
n, k = [int(i) for i in input().split()]
nums = [int(i) for i in input().split()]
res = helper(nums, k)
print(res[0],res[1]) #print(*res)

快速排序

1. 快速排序
def quickSort(arr, L, R):
    if L >= R: return
    i, j = L, R
    while i < j:
        while i < j and arr[j] >= arr[L]: j -= 1
        while i < j and arr[i] <= arr[L]: i += 1
        arr[i], arr[j] = arr[j], arr[i]
    arr[L], arr[i] = arr[i], arr[L]
    quickSort(arr, L, i-1)
    quickSort(arr, i+1, R)
    
n = int(input())
nums = list(map(int, input().split()))
quickSort(nums, 0, n-1)
print(*nums)

第三章 桶排序及排序内容总结

1. 计数排序
def countSort(nums, ):
    bucket = [0] * (max(nums)+1)
    for i in nums:
        bucket[i] += 1
    index = 0
    for i, count in enumerate(bucket):
        for _ in range(count):
            nums[index] = i
            index += 1
n = int(input())
nums = list(map(int, input().split()))
countSort(nums)
print(*nums)
2, 基数排序
def getDigit(n, d): #取出整数n第d位数
    return int((n//10**(d-1)) % 10) #将第d位放到个位,在取mod10得到个位数

def radixSort(arr, n, digit): #digit:最大的数有多少位
    radix = 10
    i, j = 0, 0
    bucket = [0] * n
    
    for d in range(1, digit + 1): #有多少位就进出多少次
        count = [0] * radix
        for num in arr:
            j = getDigit(num, d)
            count[j] += 1 
        for i in range(1, radix):
            count[i] = count[i] + count[i - 1]
        for i in range(n-1, -1, -1): # 遍历arr的数
            j = getDigit(arr[i], d) #看当前数的第d位是什么
            bucket[count[j]-1] = arr[i]
            count[j] -= 1
        arr[:] = bucket[:]
        
n = int(input())
nums =list(map(int, input().split()))
digit = len(str(max(nums)))
radixSort(nums, n, digit)
print(*nums)

第四章 链表

1. 判断一个链表是否为回文结构

方法一:使用栈

class Solution:
    def isPail(self , head: ListNode) -> bool:
        # write code here
        cur = head
        stack = []
        while cur:
            stack.append(cur.val)
            cur = cur.next
        while head:
            if head.val != stack.pop():
                return False
            head = head.next
        return True
    
#或者
class Solution:
    def isPail(self , head: ListNode) -> bool:
        # write code here
        cur = head
        stack = []
        while cur:
            stack.append(cur.val)
            cur = cur.next
        return stack == stack[::-1]

方法二:快慢指针,找到中点

空间复杂度降为O(1)

class Solution:
    def isPail(self , head: ListNode) -> bool:
        if not head or not head.next: return True
        fast = slow = head
        while fast.next and fast.next.next: #如果nexi是空的,那么next.next肯定也是空(实际上是没有)
            fast = fast.next.next
            slow = slow.next
        
        pre = None
        cur = slow.next
        slow.next = None
        while cur:
            tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp
        L, R = head, pre
        while L and R:
            Lpre = L
            if L.val != R.val:
                return False
            R = R.next
            L = L.next
        return True
2. 链表划分

给出一个长度为 n 的单链表和一个值 x ,单链表的每一个值为 listi ,请返回一个链表的头结点,要求新链表中小于 x 的节点全部在大于等于 x 的节点左侧,并且两个部分之内的节点之间与原来的链表要保持相对顺序不变。

方法一:遍历到list中做partition(荷兰国旗问题)再链接,但相对顺序会乱掉

class Solution:
    def partition(self , head: ListNode, x: int) -> ListNode:
        if not head or not head.next: return head
        nums = []
        while head:
            nums.append(head.val)
            head = head.next
        
        L, M = -1, len(nums)
        i = 0 #当前要处理得数
        while i < M:
            if nums[i] < x:
                L += 1
                nums[i], nums[L] = nums[L], nums[i]
                i += 1
            elif nums[i] == x:
                i += 1
                
            else: 
                M -= 1
                nums[i], nums[M] = nums[M], nums[i]
                
        res = cur= ListNode(nums[0])
        for num in nums[1:]:
            cur.next = ListNode(num)
            
        return res

方法二:用六个头节点将其划分保存

额外空间仍然是O(1)的

#课程的代码,分三段,但题目要求是分两段
class Solution:
    def partition(self , head: ListNode, x: int) -> ListNode:
        sH = None
        sT = None
        eH = None
        eT = None
        bH = None
        bT = None
        while head:
            tmp = head.next
            head.next = None
            if head.val < x:
                if sH == None:
                    sH = sT = head
                else:
                    sT.next = head
                    sT = sT.next
            elif head.val == x:
                if eH == None:
                    eH = eT = head
                else:
                    eT.next = head
                    eT = eT.next
            else:
                if bH == None:
                    bH = bT = head
                else:
                    bT.next = head
                    bT = bT.next
            head = tmp
        if eH:
            eT.next = bH if bH else None
        if sH:
            sT.next = eH if eH else (bH if bH else None)
        return sH if sH else (eH if eH else bH)

正解:

class Solution:
    def partition(self , head: ListNode, x: int) -> ListNode:
        sH = None
        sT = None
        eH = None
        eT = None
        while head:
            tmp = head.next
            head.next = None
            if head.val < x:
                if sH == None:
                    sH = sT = head
                else:
                    sT.next = head
                    sT = sT.next
            else:
                if eH == None:
                    eH = eT = head
                else:
                    eT.next = head
                    eT = eT.next
            head = tmp
        if sH:
            sT.next = eH if eH else None
        return sH if sH else (eH if eH else None)
3. 复制含有随机指针节点的链表

方法一:哈希表

方便找到旧节点对应的新节点

# -*- coding:utf-8 -*-
# class RandomListNode:
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None
class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        if not pHead: return 
        cur = pHead
        dic ={}
        while cur:
            dic[cur] = RandomListNode(cur.label)
            cur = cur.next
        cur = pHead
        while cur:
            dic.get(cur).next = dic.get(cur.next)
            dic.get(cur).random = dic.get(cur.random)
            cur = cur.next
        return dic[pHead]

方法二:将新节点接在旧节点的下一个也可以方便找到

class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        if not head: return 
        cur = head
        while cur:
            tmp = cur.next
            cur.next = Node(cur.val)
            cur.next.next = tmp
            cur = tmp
        cur = head
        while cur: 
            tmp = cur.next.next
            cur.next.random = cur.random.next if cur.random else None #老节点指向空,新节点也指向空
            cur = tmp
            
        res = head.next
        cur = head
        while cur:  #cur不为空,那么可以保证cur.next不为空,因为复制了一个
            tmp = cur.next.next #三个while循环都是用cur,下一个也是指向cur
            cur.next.next = cur.next.next.next if cur.next.next else None
            cur = tmp
        return res
4. 两个链表的第一个公共节点

方法一:哈希

class Solution:
    def FindFirstCommonNode(self , pHead1 , pHead2 ):
        dic = set()
        while pHead1:
            dic.add(pHead1)
            pHead1 = pHead1.next
        while pHead2:
            if pHead2 in dic:
                return pHead2
            pHead2 = pHead2.next

方法二:双指针

时间复杂度降为O(1)

class Solution:
    def FindFirstCommonNode(self , pHead1 , pHead2 ):
        p1 = pHead1
        p2 = pHead2
        while p1 != p2: #找到第一个相等的节点则返回
            p1 = p1.next if p1 else pHead2
            p2 = p2.next if p2 else pHead1
        return p1
5. 无环链表判相交

方法一:上一题双指针的方法

class CheckIntersect:
    def chkIntersect(self, headA, headB):
        # write code here
        p1 = headA
        p2 = headB
        while p1 != p2:
            p1 = p1.next if p1 else headB
            p2 = p2.next if p2 else headA
        return True if p1 else False

方法二:遍历到最后一个节点,看是否相同

class CheckIntersect:
    def chkIntersect(self, headA, headB):
        # write code here
        while headA.next:
            headA = headA.next
        while headB.next:
            headB = headB.next
        return True if headA == headB else False
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值