一、冒泡排序:
- 每次比较相邻两个数大小,然后交换, 一轮结束后,又从头开始 进行下一轮 (一共要 数组长度-1 轮 且每轮交换次数减少 并确定一个数子)
func arrSort(arr [6]int) {
for i := 0; i < len(arr); i++ {
for j := 0; j < len(arr)-i-1; j++ {
if arr[j] > arr[j+1] {
arr[j+1], arr[j] = arr[j], arr[j+1]
}
}
}
fmt.Print(arr)
}
二、快速查找(二分法)
- 先将数组排序。
- 从两边开始找数据如果找的数据小于数组最中间的数那就去数组前半段找,如果大于中间的数字就去后半段查找然后迭代
func quickFind(arr [6]int, leftIndex int, rightIndex int, findVal int) {
middle := (rightIndex + leftIndex) / 2
if rightIndex < leftIndex {
fmt.Println("没找到")
return
}
// 数组中间的数大于要查找的数据,则需要在左侧查找
if arr[middle] > findVal {
quickFind(arr, leftIndex, middle-1, findVal)
}
// 数组中间的数小于要查找的数据,则需要在右侧查找
if arr[middle] < findVal {
quickFind(arr, middle+1, rightIndex, findVal)
}
if arr[middle] == findVal {
fmt.Printf("要找的数据在第%d位置", middle)
return
}
}
三、找出字符串中没有重复字符串的最大长度(滑动窗口)
- 遍历字符串找出字符串所有的子串
- 判断每个子串有没有重复的字符,如果没有则返回最长字串的长度
func lengthOfLongestSubstring(s string) int {
var i ,j,number,length int=0,0,0,0
length=len(s);
for i=0;j<length;i++{
for j=i+1;j<length;j++{
if n:=getNumber(s,i,j);n{
if j-i>number{
number=j-i;
}
}
}
}
return number
}
func getNumber(s string,start int,end int)bool{
var m=make(map[string]string)
for i := start; i < end; i++ {
ch := s[i];
if _, ok := m[string(ch)]; ok {
return false
}
m[string(ch)]=string(ch);
}
return true;
}
四、.给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。(二分法)
请你找出并返回这两个正序数组的中位数。(进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗)
1. 将两个数组排序,合并成一个大的已经排序过的数组
2. 判断大数组的长度,如果数组长度为奇数,则中位数在正中间,如果为偶数则为最终将两个数的平均数
/**
* @param Integer[] $nums1
* @param Integer[] $nums2
* @return Float
*/
function findMedianSortedArrays($nums1, $nums2) {
$len=count($nums1)+count($nums2);
$medile=ceil($len/2)-1;// 找到中位数
$newArray=array_merge($nums1,$nums2);
sort($newArray);
if($len%2==0){
return ($newArray[$medile]+$newArray[$medile+1])/2.0;
}else{
return $newArray[$medile];
}
}
五、给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000
- 方法一:
1)找到字符串的每条字串,然后将字串反转,看能否和字串向相等,如果相等 则说明该字符串,正序和逆序每一位都相等。且长度大于之前的就更新。
function getHuiwen($str = "")
{
$strlen = strlen($str);
$temp = '';
$maxLen = 0;
$maxStr='';
for ($i = 0; $i < $strlen; $i++) {
for ($j = $i; $j < $strlen; $j++) {
$temp .= $str[$j];
$t = $temp;
if ($temp == strrev($t)) {
if (strlen($temp) > $maxLen) {
$maxLen = strlen($temp);
$maxStr=$temp;
}
}
}
$temp="";
}
return $maxStr;
}
-
方法二
1)找到字符串的每条字串,然后在字符串的反转字符串中查找如果找到了,那该字符串为对称字符串,同样对比大小更新长度最长的字符串 -
方法三
1 遍历字符串,以每个字符为中间变量(奇数情况 aba)或者相邻两个字符为中间变量(偶数情况 abba)
2.以该字符串(偶数则为这两个字符)为中心,向两边扩展找,直到两端的字符不在相等 并记录边界(二分法)
3.返回两种情况的边界最大值,并更新最大边界值 ,然后返回最大边界的字符串
六、求一个数是不是回文
1.每次除以10 求出从低到高位 的每一位 然后组装数字。和原来的数对比
1221
商 余数 组装数
122 1 1
12 2 2+1*10=12
1 2 2+12*10=122
0 1 1+122*10=1221
func isPalindrome(x int) bool {
if x <0{
return false
}
if x==0{
return true
}
y:=x
res:=0
for x>0{
res=x%10+res*10
x=x/10
}
if res==y{
return true
}
return false
}
七、求盛水最大的容器(双指针)
/*
1.正方形的面积s=xy x=两个横坐标的差 y=两个坐标最低的纵坐标 如果想面积足够大 则x和y需要更大
2.遍历数组,找到每次的面积和最大的面积比较 留最大面积
3.为保证x最大,则从数组的两边开始往中间找
4.当左边的纵坐标大于右边,则移动右边的,当右边的大于左边的则移动左边的,直到左右两边接近,则停止.
*/
func maxArea(height []int)(area int) {
var l int = 0
var r int = len(height) - 1
a := 0
for l < r {
if height[l]>=height[r]{
a = (r-l) * height[r]
}else{
a = (r-l) * height[l]
}
if a >= area {
area = a
}
if height[l] <= height[r] {
l++
} else{
r--
}
}
return area
}
八、整数转罗马数字(贪心算法)
/**
数字转罗马数字
1.找符合的罗马数字,每次从最大的开始找。找到一个后,继续找剩下数的最大罗马数字
2.整理出所有罗马数字对应的整数列表
3.在整理的整数列表中找最大满足输入数字的
4.始终找最大的符合输入数字的
5.找到一个最大的罗马数字后将剩下的数(输入的数减去已经找到的数)继续找剩下的罗马数字
*/
func intToRoman(num int) (result string) {
var intNumArr = [13]int{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}
var romanArr = [13]string{"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}
var romanNumber = len(romanArr)
for i := 0; i < romanNumber; i++ {
for ; num >= intNumArr[i]; {
result += romanArr[i]
num = num - intNumArr[i]
}
}
return result
}
九、求数组字符串最长公共前缀(横向扫描)
编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。
示例 1:
输入:strs = ["flower","flow","flight"]
输出:"fl"
/*
找出字符串数组中最长的公共前缀
1.遍历数组中的每个字符串,找到最短长度作为边界,即公共前缀的最大长度
2.遍历数组中每个字符串,比较他们的第一位是否相等,如果相等则比较第二位,将第一位添加到前缀中
3.直到出现不相等或超出边界。
4.返回公共前缀。
*/
func LongestCommonPrefix(strArr []string) (res string) {
var lenght = len(strArr)
if lenght==0{
return ""
}
var minLen = 100000
for i := 0; i < lenght; i++ {
if minLen >= len(strArr[i]) {
minLen = len(strArr[i])
}
}
for j := 0; j < minLen; j++ {
v := string(strArr[0][j])
f := 0
for i := 0; i < lenght; i++ {
value := string(strArr[i][j])
if value != v {
f = 1
break
}
}
if f == 0 {
res += v
}else{
break;
}
}
return res
}
十、选择排序
/*
1)先找出数组(n)中最大的然后和数组第一个交换
2)从数组剩下(n-1)中找最大的和第二个交换
3)依次类推(n-1)次
*/
func SelectSort(arr []int) {
maxIndex := 0
length := len(arr)
for j := 0; j < length-1; j++ {
maxNum := (arr)[j]
maxIndex = j
for i := j + 1; i < length; i++ {
if maxNum < (arr)[i] {
maxNum = (arr)[i]
maxIndex = i
}
}
if maxIndex != j {
(arr)[j], (arr)[maxIndex] = (arr)[maxIndex], (arr)[j]
}
}
}
十一、三个数的和等于0(排序+双指针)
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
/*
1.特判,对于数组长度 nn,如果数组为 null 或者数组长度小于 3,返回 []。
2.对数组进行排序。(可选择排序)
3.遍历排序后数组:
若 nums[i]>0:因为已经排序好,所以后面不可能有三个数加和等于 00,直接返回结果。
对于重复元素:跳过,避免出现重复解
令左指针 L=i+1,右指针 R=n-1R=n−1,当 L<R 时,执行循环:
当 nums[i]+nums[L]+nums[R]==0,执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将 L,R 移到下一位置,寻找新的解
若和大于 0,说明 nums[R] 太大,R 左移
若和小于 0,说明 nums[L] 太小,L 右移
*/
func ThreeSumDoublePointer(arr []int) (result [][]int) {
arrLen := len(arr)
if len(arr) < 3 {
return result
}
for i := 0; i < arrLen; i++ {
if arr[i] > 0 {
return result
}
if i > 0 && arr[i] == arr[i-1] {
continue
}
L := i + 1
R := arrLen - 1
for L < R {
if arr[i]+arr[L]+arr[R] == 0 {
result = append(result, []int{arr[i], arr[L], arr[R]})
for L < R && arr[L] == arr[L+1] {
L = L + 1
}
for L < R && arr[R] == arr[R-1] {
R = R - 1
}
L = L + 1
R = R - 1
} else if arr[i]+arr[L]+arr[R] > 0 {
R = R - 1
} else {
L = L + 1
}
}
}
return result
}
十二、电话号码的字母组合
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
/*
给定一个仅包含数字2-9的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母
1.每次处理一个输入字符对应的字符串数组 例如 2 res=(a,b,c )
2.每次将本次次输入的字符(3)对应的字符串数组(d,e,f)与上一次处理的字符串数组结果res=(a,b,c)组合结果res= (ad,ae,ef,bd,be,ef,cd,ce,cf)
3.再一次将本次输入的字符(4)对应的字符串数组(g,h,i)与上一次处理的字符串结果res= (ad,ae,ef,bd,be,ef,cd,ce,cf)
4.以此类推
*/
func LetterCombinAtions(digits string) (res []string) {
dicMap := make(map[string][]string)
dicMap["2"] = []string{"a", "b", "c"}
dicMap["3"] = []string{"d", "e", "f"}
dicMap["4"] = []string{"g", "h", "i"}
dicMap["5"] = []string{"j", "k", "l"}
dicMap["6"] = []string{"m", "n", "o"}
dicMap["7"] = []string{"p", "q", "r", "s"}
dicMap["8"] = []string{"t", "u", "v"}
dicMap["9"] = []string{"w", "x", "y", "z"}
digitsLen := len(digits)
for i := 0; i < digitsLen; i++ {
if len(res) > 0 {
var temp []string
for j := 0; j < len(res); j++ {
var valueArr = dicMap[string(digits[i])]
for k := 0; k < len(valueArr); k++ {
temp = append(temp, res[j]+valueArr[k])
}
}
res = temp
} else {
var valueArr = dicMap[string(digits[i])]
for j := 0; j < len(valueArr); j++ {
res = append(res, valueArr[j])
}
}
}
return res
}
十三、删除链表的倒数第 N 个结点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?
下面的两个解答没有考虑极端情况,比如N小于链表长度的地方。或者n刚好等于链表的长度。
/*
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
1.使用快慢指针,都指向头节点
2.将快指针往后走到n+1步,此时快慢指针之间正好相差n个节点
3.同时将快慢指针往后走,当快指针指向最后一格的时候,慢指针正好指向的倒数第n个节点前面一位节点。
4.将慢指针指向n结点的下一个节点。
*/
func removeNthFromEnd1(head *ListNode, n int) *ListNode {
slowNode := head
flastNode := head
for i := 0; i <= n; i++ {
if flastNode != nil {
flastNode = flastNode.Next
}
}
for flastNode != nil {
flastNode = flastNode.Next
slowNode = slowNode.Next
}
if slowNode.Next != nil {
if slowNode.Next.Next==nil{
return slowNode.Next
}else{
slowNode.Next = slowNode.Next.Next
}
} else {
if n == 1 && slowNode.Next == nil {
return slowNode
} else {
slowNode.Next = nil
}
}
return head
}
/*
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
1.遍历头节点算出倒数第n个节点属于整数第几个节点的位置
2.遍历头节点到正数的位置。然后将该节点指向下下一个节点。
*/
func removeNthFromEnd(head *ListNode, n int) *ListNode {
if head.Next == nil {
head = nil
return head
}
temp := head
number := 0
deleteNumber := 0
for temp.Next != nil {
temp = temp.Next
number++
}
deleteNumber = number - n
curentNumber := 0
temp = head
fmt.Println(deleteNumber)
for temp.Next != nil {
temp = temp.Next
curentNumber++
if curentNumber == deleteNumber {
if temp.Next.Next != nil {
temp.Next = temp.Next.Next
} else {
temp.Next = nil
}
}
}
return head
}
十四、合并两个有序链表(递归)
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
/*
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
1.两组升序排列好的队列a=[1,3,4] b=[1,2,5],每次各取队列的第一位 1,1 相比较较小的第一位 1放新队列的第一位res=[1] ,此时 a=[3,4] b=[1,2,5]
2.将剩下的 a=[3,4] b=[1,2,5] 继续比较,将比较小的b的第一位 1 放新列表后面 res=[1,1] 此时 a=[3,4] b=[2,5]
3.将剩下的 a=[3,4] b=[2,5] 就继续比较将较小的b的第一位 2 放新列表后面 res=[1,1,2] 此时 a=[3,4] b=[5]
继续递归直到结束
*/
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
if l1 == nil {
return l2
}
if l2 == nil {
return l1
}
var res *ListNode
if l1.Val >= l2.Val {
res = l2
res.Next = mergeTwoLists(l1, l2.Next)
} else {
res = l1
res.Next = mergeTwoLists(l1.Next, l2)
}
return res
}
十五、100亿数据找出最大的1000个数字(top k问题)
1)全部排序,找前10000个,不靠谱,时间长
2)局部淘汰法:将前1000个放一个容器,后面的来和这个容器最小的比较,大于就删除最小的插入该数,小于则不管
3)分治法:将100亿的数据做1000分区,找出每个分区里的前1000个数,然后将这些数在合并找前1000个数
4)hash法,去掉重复的数据后采用分治法。