1. 程式人生 > >演算法思想:排序

演算法思想:排序

排序是實際運用中比較常見的情況。計算機界也對排序進行了很深入的研究。常見的排序演算法有:快速排序、歸併排序、插入排序、堆排序等等。
在一些演算法題目當中,排序經常是作為一個實現的前提條件。比如求解 Kth Element 問題或者 TopK Elements 問題。
LeedCode中就有一些題目是需要採用排序解決或者解決排序問題。
1、找到第K大元素
215. Kth Largest Element in an Array (Medium)
題目可以採用各種方法:如各種排序演算法、K個元素的堆排序等。。

/*採用go語言自帶的排序演算法(快排)後直接返回倒數第K個元素*/
func
findKthLargest(nums []int, k int) int { sort.Sort(sort.IntSlice(nums)) length := len(nums) return nums[length-k] }
/*Java的優先順序序列來作為堆實現*/
public int findKthLargest(int[] nums, int k) {
    PriorityQueue<Integer> pq = new PriorityQueue<>(); // 小頂堆
    for (int val : nums) {
        pq.
add(val); if (pq.size() > k) // 維護堆的大小為 K pq.poll(); } return pq.peek(); }

2、桶排序
如題目1:出現頻率最多的 k 個數
347. Top K Frequent Elements (Medium)

Given [1,1,1,2,2,3] and k = 2, return [1,2].
//利用桶排序。
func topKFrequent(nums []int, k int) []int {
    //1、先統計各個數字出現的次數
    var m =
make(map[int]int) for _,v := range nums { if val,ok := m[v];ok{ m[v] = val+1 }else { m[v] = 1 } } //此時m為統計好的各個數字出現次數的map //2、利用桶,下標表示出現的次數,val是個list,存放相同次數的數字。 var bucket = make([][]int,len(nums)+1) for k,v := range m { if bucket[v] == nil { temp := []int{k} bucket[v] = temp }else { bucket[v] = append(bucket[v],k) } } //此時bucket是按照次數出現的桶 //3、從後往前遍歷通,拿到要出現的單詞 var result []int for i:=len(bucket)-1;i!=0&&k!=0;i-- { if bucket[i] != nil { result = append(result, bucket[i]...) k = k-len(bucket[i]) } } return result }

題目2:按照字元出現次數對字串排序
451. Sort Characters By Frequency (Medium)

Input:
"tree"

Output:
"eert"

Explanation:
'e' appears twice while 'r' and 't' both appear once.
So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer.
//利用桶排序。
func frequencySort(s string) string {
    bt := []byte(s)
     //1、先統計各個字母出現的次數
     var m = make(map[byte]int)
     for _,v := range bt {
        if val,ok := m[v];ok{
            m[v] = val+1
        }else {
            m[v] = 1
        }
    }
    //此時m為統計好的各個字母出現次數的map
    //2、利用桶,下標表示出現的次數,val是個list,存放相同次數的字母。
    var bucket = make([][]byte,len(s)+1)
    for k,v := range m {
        if bucket[v] == nil {
            temp := []byte{k}
            bucket[v] = temp
        }else {
            bucket[v] = append(bucket[v],k)
        }
    }
     //此時bucket是按照次數出現的桶
    //3、從後往前遍歷通,拿到要出現的單詞
    var result []byte
    for i:=len(bucket)-1;i!=0;i-- {
        if bucket[i] != nil {
            for k:=0;k!=len(bucket[i]);k++ {
                for j:=0;j!=i;j++ {
                    result = append(result,bucket[i][k])
                }
            }
        }
    }
    return string(result)
}

3、雙(多)指標+排序
問題:荷蘭國旗問題
荷蘭國旗包含三種顏色:紅、白、藍。

有三種顏色的球,演算法的目標是將這三種球按顏色順序正確地排列。

它其實是三向切分快速排序的一種變種,在三向切分快速排序中,每次切分都將陣列分成三個區間:小於切分元素、等於切分元素、大於切分元素,而該演算法是將陣列分成三個區間:等於紅色、等於白色、等於藍色。
75. Sort Colors (Medium)

Input: [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]
/*採用前後兩個指標指向兩端的顏色標記然後用一個遍歷指標從前往後遍歷,
遇到red或者blue則交換到相應red和blue指標的位置,
然後繼續往前找(注意邊界關係,
搜尋指標找到red交換後要繼續往前,找到blue的時候不能往前還要比較一次,
當搜尋指標與blue相遇時也要比一次)*/

func sortColors(nums []int)  {
    l,r := 0,len(nums)-1;
    for i:=0;i<= r;{
        if nums[i] == 0 { //掃描到red
            swap(nums,i,l)
            l++
            i++
        }else if  nums[i] == 2 { //掃描到blue
            swap(nums,i,r)
            r--
        }else {
            i++
        }
    }
}

func swap(nums []int,i int, j int) {
    temp := nums[i]
    nums[i] = nums[j]
    nums[j] = temp
}

思考:如果是K個元素如此排序怎麼辦。