Skip to content

Latest commit

 

History

History
248 lines (182 loc) · 5.77 KB

algorithm.md

File metadata and controls

248 lines (182 loc) · 5.77 KB

自己的算法练习记录

1. 两个数组的交集(第350)

给定两个数组,编写一个函数计算他们的交集

示例1:

输入: nums1 = [1, 2, 2, 1], num2 = [2, 2]

输出: [2,2]

示例2:

输入: nums1 = [4, 9, 5], num2 = [9, 4, 9, 8, 4]

输出: [4, 9]

说明: 输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。 我们可以不考虑输出结果的顺序。 进阶: 如果给定的数组已经排好序呢?将如何优化你的算法呢? 思路:设定两个为0的指针,比较两个指针的元素是否相等。如果指针的元素相等,我们将两个指针一 起向后移动,并且将相等的元素放入空白数组。

优秀解答

// 解法一, 针对所有列表
func intersect1(nums1 []int, nums2 []int) []int {
	m0 := map[int]int{}
	for _, v := range nums1{
		m0[v] += 1
	}
	k := 0
	for _, v := range nums2{
		if m0[v] > 0{
			m0[v] -= 1
			nums2[k] = v
			k++
		}
	}
	return nums2[0:k]
}

// 解法二: 针对有序的列表

func intersect2(nums1 []int, nums2 []int) []int {
	i, j, k := 0, 0, 0
	sort.Ints(nums1)
	sort.Ints(nums2)
	for i < len(nums1) && j < len(nums2){
		if nums1[i] > nums2[j] {
			j++
		} else if nums1[i] < nums2[j]{
			i++
		} else {
			nums1[k] = nums1[j]
			i++
			j++
			k++
		}
	}
	return nums[:k]
}

2. 最长公共前缀(14)

编写一个函数来查找数组中最长的公共前缀,如果不存在公共前缀,则返回“”

示例1:

输入: ["flower","flow","flight"]
输出: "fl"

示例2:

输入: ["dog","racecar","car"]
输出: ""

教程里面用到了go的strings.Index(返回子串seq在字符串s中第一次出现的位置,没有返回-1)

思路:

拿第一个字符串全部字符去对每一个字符串,没有找到公共前缀那么就字符串从末尾切片,一个一个的切片,直到找到公共前缀或者没有

func longestCommonPrefix(strs []string) string{
    if len(strs) < 1{
        return ""
    }
    prefix := strs[0]
    for _,k := range strs {
        for strings.Index(k, prefix) != 0{
            if len(prefix) == 0 {
                return ""
            }
            prefix  = prefix[: len(prefix) - 1]
        }
    }
    return prefix
}

3. 买股票的最佳时机(122)

第122题:买卖股票的最佳时机 II

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的 最大利润。注意你不能在买入股票前卖出股票。

示例 1:

输入: [7,1,5,3,6,4]
输出: 7

解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格= 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 示例 2:

输入: [1,2,3,4,5]
输出: 4

解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 -1 = 4 。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例3:

输入: [7,6,4,3,1]
输出: 0

解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

思路:

  • 不能参与多笔交易。只能买进一笔,卖出后才能再次买进
  • 尽可能的多进行交易
func maxProfit(prices []int) int {
if len(prices) < 2 {
		return 0
	}
	dp := make([][2]int, len(prices))
	dp[0][0] = 0
	dp[0][1] = -prices[0]
	for i := 1; i < len(prices); i++ {
		dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
		dp[i][1] = max(dp[i-1][0]- prices[i], dp[i-1][1])
	}
	return dp[len(prices) - 1][0]
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

题目扩展

图解的方式其实在各种算法题中,屡见不鲜。而我们通过图解的方式,也可以抽丝剥茧一样,一层一层 剥掉算法题目的外壳,寻找到最直观的解题思路,直捣黄....咳咳,直奔核心。那我们又如何用图解的观 察方式,来对本系列的其他题目寻找到一种通用解法,来规避题目中的陷阱呢?浩仔讲算法,我们下期 再见喽!

4. 旋转数组(189)

题目189: 旋转数组

给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

示例1:

输入: [1,2,3,4,5,6,7] 和 k = 3
输出: [5,6,7,1,2,3,4]

解释:

  • 向右旋转 1 步: [7,1,2,3,4,5,6]
  • 向右旋转 2 步: [6,7,1,2,3,4,5]
  • 向右旋转 3 步: [5,6,7,1,2,3,4]

示例 2:

输入: [-1,-100,3,99] 和 k = 2
输出: [3,99,-1,-100]

解释:

  • 向右旋转 1 步: [99,-1,-100,3]
  • 向右旋转 2 步: [3,99,-1,-100]

说明:

尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。

要求使用空间复杂度为 O(1) 的 原地 算法。

这道题如果不要求原地翻转的话,其实相当简单。但是原地翻转的方法却并不容易想到,我们直接看题解。

题目图解

这个方法基于这个事实:若我们需要将数组中的元素向右移动 k 个位置, 那么 k%l (l为数组长度) 的尾部元素会被移动到头部,剩下的元素会被向后移动。

思路:

先将整个数组反转,然后将前面k个元素反转,再将l-k个元素反转

func rotate(nums []int, k int){
    reverse(nums)
    reverse(nums[:k%len(nums)])
    reverse(nums[k%len(nums):])
}

func reverse(arr []int){
    for i := 0; i < len(arr)/2; i ++{
        arr[i], arr[len(arr)-i -1] = arr[len(arr)-i -1], arr[i]
    }
}