1. 程式人生 > >分治法:關於選擇演算法,找最大,找最小,同時找最大和最小,找第二大

分治法:關於選擇演算法,找最大,找最小,同時找最大和最小,找第二大

找最大或者最小,蠻力演算法為最優的演算法,需要比較n-1次

# 這個已經是最優的演算法了,比較n-1次
def findMax(arr):
    max_pivot = arr[0]
    
    for i in range(1,len(arr)):
        if arr[i] > max_pivot:
            max_pivot = arr[i]
    
    return max_pivot

def findMin(arr):
    min_pivot = arr[0]
    
    for i in range(1,len(arr)
): if arr[i] < min_pivot: min_pivot = arr[i] return min_pivot

還有一種分治的演算法,也是需要比較n-1次,類似於錦標賽,這裡比較次數就是淘汰掉的隊伍個數,劃分子問題的方法就是兩兩比較,只留最大,注意奇數的處理(直接晉級下輪)

# 兩兩比較得到最大的一半陣列
def partition_max(arr):
    
    pointer = 0
    max_arr =[]
    
    while pointer <= len(arr)-2:
        max_arr +=
[max(arr[pointer],arr[pointer+1])] pointer +=2 # 假如是奇數,加上最後一個數,偶數的話加的為空 max_arr +=arr[pointer:] return max_arr # 找最大分治的寫法,也是最優的為比較n-1次 def findmax_recursive(arr): if len(arr) == 1: return arr[0] max_arr = partition_max(arr) return findmax_recursive(
max_arr)

同時找最大和找最小,蠻力演算法,找最大n-1,找最小n-2,合計2n-3

使用分組的方式比較次數:3/2 *n -2

# 找最大和最小,得到最大一半分組和最小的一半分組
def partition_max_min(arr):
    
    pointer = 0
    max_arr =[]
    min_arr =[]
    
    while pointer <= len(arr)-2:
        if arr[pointer] >=arr[pointer+1]:
            max_arr.append(arr[pointer])
            min_arr.append(arr[pointer+1])
        else:
            max_arr.append(arr[pointer+1])
            min_arr.append(arr[pointer])
            
        pointer +=2
        
    max_arr +=arr[pointer:]
    min_arr +=arr[pointer:]
    
    return max_arr,min_arr

# 這個也是最優的演算法了
def findMaxMin(arr):
    max_arr,min_arr = partition_max_min(arr)
    min = findMin(min_arr)
    max = findMax(max_arr)
    
    return max,min

找第二大,蠻力演算法也是2n-3,採取錦標賽的方式冠軍比較n-1次,亞軍在冠軍的手下敗將裡產生比較logn-1次,這裡需要備忘冠軍的手下敗將,但是一開始冠軍不知道,所以每個選手需要記錄他曾經打敗過的選手

#%%
class node:
    def __init__(self,value=None,miss=None):
        self.value = value
        self.miss =miss
    
def partition_max_with_nodes(arr):
    
    pointer = 0
    max_arr =[]
    
    while pointer <= len(arr)-2:
        if arr[pointer].value >=arr[pointer+1].value:
            
            arr[pointer].miss.append(arr[pointer+1].value)
            max_arr.append(arr[pointer])
        else:
            arr[pointer+1].miss.append(arr[pointer].value)
            max_arr.append(arr[pointer+1])
            
        pointer +=2
    # 假如是奇數,加上最後一個數,偶數的話加的為空   
    max_arr +=arr[pointer:]
    
    return max_arr
    
def findMaxSecondmax(arr):
    arr_node =[]
    for i in range(len(arr)):
        arr_node.append(node(arr[i],[]))
        
    def findmax_recursive(arr):
        if len(arr) == 1:
            return arr[0]
        
        max_arr = partition_max_with_nodes(arr)
        return findmax_recursive(max_arr)
    
    pair = findmax_recursive(arr_node)
    
    first_max = pair.value
    second_max_arr = pair.miss
    
    second_max = findMax(second_max_arr)
    return first_max,second_max
        

arr = [4,44,5,77,8,32,18,99,377,55,33,11,12,999,678]
print(arr)
##print(findMax(arr))
##print(partition_max(arr))
##print(findmax_recursive(arr))
#print(partition_max_min(arr))
#print(findMaxMin(arr))
print(findMaxSecondmax(arr))

[4, 44, 5, 77, 8, 32, 18, 99, 377, 55, 33, 11, 12, 999, 678]
(999, 678)

對於一般情況下次再研究