Skip to content

算法

INFO

烦死了

摩尔投票法

  用于找出一堆数字中出现频率大于一半的算法,即找出众数。

实现方式

  遍历一次数组,记录两个值,一个是当前记录的数字和这个数字剩余的次数。

go
func majorityElement(nums []int) int {
	var maxNum int
	occurTime := 0
	for _, v := range nums {
		if v != maxNum {
			if occurTime == 0 {
				maxNum = v
				occurTime++
			} else {
                occurTime--
            }
		} else {
            occurTime++
        }
	}
    return maxNum
}

复杂度

  • 时间复杂度:O(n)
  • 空间负责度:O(1)

双指针

  经常用到,例如删除有序数组中的重复项,或者计算两数之和

删除有序数组中的重复项

go
func removeDuplicates(nums []int) int {
    n := len(nums)
    if n == 0 {
        return 0
    }
    slow := 1
    for fast := 1; fast < n; fast++ {
        if nums[fast] != nums[fast-1] {
            nums[slow] = nums[fast]
            slow++
        }
    }
    return slow
}

两数之和

  寻找一个非递减数组中两数之和等于某特定数字的两数。   初始时两个指针分别指向第一个元素位置和最后一个元素的位置。每次计算两个指针指向的两个元素之和,并和目标值比较。如果两个元素之和等于目标值,则发现了唯一解。如果两个元素之和小于目标值,则将左侧指针右移一位。如果两个元素之和大于目标值,则将右侧指针左移一位。移动指针之后,重复上述操作,直到找到答案。

KMP算法

  用来在一个主文本字符串中查找一个模式字符串的出现位置。大学数据结构中的经典算法,还是挺难的。

实现方式

  对于模式字符串,要先算一个next数组。next数组就是一个前缀表(prefix table)。前缀表是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。   前缀表代表的意思是该字符串中最长相同前后缀的长度,前后缀都是从左往右读。例如:aabaaf对应的前缀表就是010120

go
func computePrefix(pattern string) []int {
    prefix := make([]int, len(pattern))
    j := 0
    for i := 1; i < len(pattern); {
        if pattern[i] == pattern[j] {
            j++
            prefix[i] = j
            i++
        } else {
            if j != 0 {
                j = prefix[j-1]
            } else {
                prefix[i] = 0
                i++
            }
        }
    }
    return prefix
}
go
func kmpSearch(text, pattern string, next []int) []int {
  positions := []int{}
  j := 0
  
  for i := 0; i < len(text); {
    if text[i] == pattern[j] {
      i++
      j++
      
      if j == len(pattern) {
        positions = append(positions, i-j)
        j = next[j-1] // 继续寻找下一个匹配
      }
    } else {
      if j != 0 {
        j = next[j-1]
      } else {
        i++
      }
    }
  }
  return positions
}

  具体的比较方法,每次退回到next[j-1]

复杂度

  • 时间复杂度:O(m+n)

快速排序

go
package main

import (
    "fmt"
)

func quickSort(arr []int,l int,r int) {
  if l>=r {
    return
  }
  pivot,i,j:=arr[l+(r-l)/2],l,r
  for i<=j{
    for arr[i]<pivot {
      i++
    }
    for arr[j]>pivot {
      j--
    }
    if i<=j {
      arr[i], arr[j] = arr[j], arr[i]
      i++
      j--
    }
  }
  fmt.Println(l,r)
  fmt.Println(arr)
  quickSort(arr,l,j)
  quickSort(arr,i,r)
}

func main() {
    var n int
    fmt.Scanf("%d",&n)
    arr:=make([]int,n)
    for i:=0;i<n;i++{
      fmt.Scanf("%d",&arr[i])
    }
    quickSort(arr,0,len(arr)-1)
    for _,n := range arr {
      fmt.Printf("%d ",n)
    }

}

归并排序

go
package main

import (
  "fmt"
)

func mergeSort(arr []int) []int {
  if len(arr)==1 {
    return arr
  } else if len(arr)==2 {
    if arr[0]>arr[1] {
      arr[1],arr[0] = arr[0],arr[1]
    }
    return arr
  }
  middle := len(arr)/2
  left := mergeSort(arr[0:middle])
  right := mergeSort(arr[middle:])
  var temp_arr []int
  i,j := 0,0
  for {
    if i>=len(left) {
      temp_arr = append(temp_arr,right[j:]...)
      return temp_arr
    } else if j>=len(right) {
      temp_arr = append(temp_arr,left[i:]...)
      return temp_arr
    }
    if left[i]<right[j] {
      temp_arr = append(temp_arr,left[i])
      i++
    } else {
      temp_arr = append(temp_arr,right[j])
      j++
    }
  }
}

func main() {
  var k int
  fmt.Scanf("%d",&k)
  arr := make([]int,k)
  for i:=0;i<k;i++ {
    fmt.Scanf("%d",&arr[i])
  }
  arrs := mergeSort(arr)
  for i:=0;i<len(arrs);i++ {
    fmt.Printf("%d ",arrs[i])
  }
}