feat(Go-StudyExample):2020/12/25:新增leetcode部分习题(数据结构、二进制相关)
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/12/21 22:26
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package simple
|
||||
|
||||
type Doc interface {
|
||||
Description(string) string
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/12/22 14:23
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package simple
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type FindDisappearedNumbers struct{}
|
||||
|
||||
func (FindDisappearedNumbers) Description(string) string {
|
||||
return `
|
||||
给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。
|
||||
|
||||
找到所有在 [1, n] 范围之间没有出现在数组中的数字。
|
||||
|
||||
您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。
|
||||
|
||||
示例:
|
||||
|
||||
输入:
|
||||
[4,3,2,7,8,2,3,1]
|
||||
|
||||
输出:
|
||||
[5,6]
|
||||
|
||||
`
|
||||
}
|
||||
|
||||
//思路分析:
|
||||
// *
|
||||
// * 找出 1 - n 中没有出现的数字。不能使用额外的空间,两次循环时间复杂度为 2O(n),即为 O(n)。
|
||||
// *
|
||||
// * 解题思路:使用数组的下标来标记数字的出现于否,通过一遍遍历即可标记出全部已经出现的数组
|
||||
// *
|
||||
// * [4,3,2,7,8,2,3,1] 初始数据
|
||||
// *
|
||||
// * [4,3,2,-7,8,2,3,1] 第一个数据 4 出现,将数组的第四个也就是下标 3 的数据修改为负数。-7 计算时,通过绝对值处理一下即可不影响数据的计算
|
||||
// * [4,3,-2,-7,8,2,3,1]
|
||||
// * [4,-3,-2,-7,8,2,3,1]
|
||||
// * [4,-3,-2,-7,8,2,-3,1]
|
||||
// * [4,-3,-2,-7,8,2,-3,-1]
|
||||
// * [4,-3,-2,-7,8,2,-3,-1]
|
||||
// * [4,-3,-2,-7,8,2,-3,-1]
|
||||
// * [-4,-3,-2,-7,8,2,-3,-1]
|
||||
// *
|
||||
// * 计算结束,数组的第五个,第六个依然为整数,证明 5,6 没有出现
|
||||
// *
|
||||
func findDisappearedNumbers(nums []int) []int {
|
||||
list := make([]int, 0)
|
||||
for _, num := range nums {
|
||||
nums[toPositive(num)-1] = -toPositive(nums[toPositive(num)-1])
|
||||
}
|
||||
|
||||
for index, num := range nums {
|
||||
if num >= 1 {
|
||||
list = append(list, index+1)
|
||||
}
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
func toPositive(num int) int {
|
||||
if num < 0 {
|
||||
return -num
|
||||
}
|
||||
return num
|
||||
}
|
||||
|
||||
func TestFindDisappearedNumbers(t *testing.T) {
|
||||
fmt.Println(findDisappearedNumbers([]int{4, 3, 2, 7, 8, 2, 3, 1}))
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/12/21 22:26
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package simple
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type GroupAnagrams struct{}
|
||||
|
||||
func (GroupAnagrams) Description(string) string {
|
||||
return `
|
||||
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
|
||||
|
||||
示例:
|
||||
|
||||
输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
|
||||
输出:
|
||||
[
|
||||
["ate","eat","tea"],
|
||||
["nat","tan"],
|
||||
["bat"]
|
||||
]
|
||||
说明:
|
||||
|
||||
所有输入均为小写字母。
|
||||
不考虑答案输出的顺序。
|
||||
|
||||
`
|
||||
}
|
||||
|
||||
//思路分析:定义26个质数作为字母的哈希,因为题目要求都是小写字母,并且质数相乘不会出现相同(三个不同的质数相乘的结果一定不一样)
|
||||
//如果单词中包含的是是完全不同的字母。还可以使用二进制32位的26位来表示,性能更好
|
||||
var prime = []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103}
|
||||
|
||||
func groupAnagrams(strs []string) [][]string {
|
||||
m := make(map[int][]string, 0)
|
||||
for _, str := range strs {
|
||||
num := 1
|
||||
for _, b := range []byte(str) {
|
||||
num = num * prime[int(b-97)]
|
||||
}
|
||||
if _, ok := m[num]; ok {
|
||||
m[num] = append(m[num], str)
|
||||
continue
|
||||
}
|
||||
m[num] = []string{str}
|
||||
}
|
||||
|
||||
list := make([][]string, 0)
|
||||
for _, value := range m {
|
||||
list = append(list, value)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func TestGroupAnagrams(t *testing.T) {
|
||||
for _, row := range groupAnagrams([]string{"eat", "tea", "tan", "ate", "nat", "bat"}) {
|
||||
fmt.Println(row)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/12/22 11:53
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package simple
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type IsAnagram struct{}
|
||||
|
||||
func (IsAnagram) Description(string) string {
|
||||
return `
|
||||
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
|
||||
|
||||
示例 1:
|
||||
|
||||
输入: s = "anagram", t = "nagaram"
|
||||
输出: true
|
||||
示例 2:
|
||||
|
||||
输入: s = "rat", t = "car"
|
||||
输出: false
|
||||
说明:
|
||||
你可以假设字符串只包含小写字母。
|
||||
|
||||
进阶:
|
||||
如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?
|
||||
`
|
||||
}
|
||||
|
||||
//思路分析:因为这边只提到了26个字母.所以声明长度为26的数组,在字符串t中出现的字符位 + 1 ,在字符串s中出现的字符位 -1,达到抵消的效果,最后如果数组都为0,就是异位数,否则不是
|
||||
//这个题目还可以使用排序、前缀树 map 等方法处理
|
||||
func isAnagram(s string, t string) bool {
|
||||
if len(s) != len(t) {
|
||||
return false
|
||||
}
|
||||
num := [26]int{}
|
||||
|
||||
sb := []byte(s)
|
||||
tb := []byte(t)
|
||||
for i := 0; i < len(s); i++ {
|
||||
num[sb[i]-'a']++
|
||||
num[tb[i]-'a']--
|
||||
}
|
||||
|
||||
for _, r := range num {
|
||||
if r != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func TestIsAnagram(t *testing.T) {
|
||||
fmt.Println(isAnagram("axmsdawd", "dwsadmxa"))
|
||||
fmt.Println(isAnagram("axmsdawd", "dwsadmxb"))
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/12/21 23:01
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package simple
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type LongestCommonPrefix struct{}
|
||||
|
||||
func (LongestCommonPrefix) Description(string) string {
|
||||
return `
|
||||
编写一个函数来查找字符串数组中的最长公共前缀。
|
||||
|
||||
如果不存在公共前缀,返回空字符串 ""。
|
||||
|
||||
示例 1:
|
||||
|
||||
输入: ["flower","flow","flight"]
|
||||
输出: "fl"
|
||||
示例 2:
|
||||
|
||||
输入: ["dog","racecar","car"]
|
||||
输出: ""
|
||||
解释: 输入不存在公共前缀。
|
||||
`
|
||||
}
|
||||
|
||||
//思路分析:最长前缀其实就是求最长字符串长度.所以第一个字符串作为公共字符串,然后循环所有的字符串,进行公共字符串的缩减
|
||||
func longestCommonPrefix(strs []string) string {
|
||||
if len(strs) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
var match []byte
|
||||
for index, str := range strs {
|
||||
if index == 0 {
|
||||
match = []byte(str)
|
||||
continue
|
||||
}
|
||||
position := getPosition(match, str)
|
||||
match = match[0:position]
|
||||
}
|
||||
|
||||
return string(match)
|
||||
}
|
||||
|
||||
func getPosition(match []byte, str string) int {
|
||||
var position int
|
||||
for i, m := range []byte(str) {
|
||||
if len(match)-1 < i {
|
||||
break
|
||||
}
|
||||
if m == match[i] {
|
||||
position++
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return position
|
||||
}
|
||||
|
||||
func TestLongestCommonPrefix(t *testing.T) {
|
||||
fmt.Println(longestCommonPrefix([]string{"flower", "flow", "flight"}))
|
||||
fmt.Println(longestCommonPrefix([]string{"flow", "flower", "flight"}))
|
||||
fmt.Println(longestCommonPrefix([]string{"dog", "racecar", "car"}))
|
||||
fmt.Println(longestCommonPrefix([]string{"cir", "car"}))
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/12/24 15:18
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package simple
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type MajorityElement1 struct{}
|
||||
|
||||
func (MajorityElement1) Description(string) string {
|
||||
return `
|
||||
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
|
||||
|
||||
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
|
||||
|
||||
示例 1:
|
||||
输入: [3,2,3]
|
||||
输出: 3
|
||||
|
||||
示例 2:
|
||||
输入: [2,2,1,1,1,2,2]
|
||||
输出: 2
|
||||
`
|
||||
}
|
||||
|
||||
//思路说明:
|
||||
func majorityElement1(nums []int) int {
|
||||
var result, count int
|
||||
for _, num := range nums {
|
||||
if count == 0 {
|
||||
result = num
|
||||
count++
|
||||
continue
|
||||
}
|
||||
if num == result {
|
||||
count++
|
||||
continue
|
||||
}
|
||||
count--
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func TestMajorityElement1(t *testing.T) {
|
||||
fmt.Println(majorityElement1([]int{3, 2, 3}))
|
||||
fmt.Println(majorityElement1([]int{2, 2, 1, 1, 1, 2, 2}))
|
||||
fmt.Println(majorityElement1([]int{3, 3, 4}))
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/12/23 16:37
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package simple
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type MajorityElement2 struct{}
|
||||
|
||||
func (MajorityElement2) Description(string) string {
|
||||
return `
|
||||
给定一个大小为 n 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。
|
||||
|
||||
进阶:尝试设计时间复杂度为 O(n)、空间复杂度为 O(1)的算法解决此问题。
|
||||
|
||||
示例 1:
|
||||
|
||||
输入:[3,2,3]
|
||||
输出:[3]
|
||||
|
||||
示例 2:
|
||||
|
||||
输入:nums = [1]
|
||||
输出:[1]
|
||||
|
||||
示例 3:
|
||||
|
||||
输入:[1,1,1,3,3,2,2,2]
|
||||
输出:[1,2]
|
||||
|
||||
`
|
||||
}
|
||||
|
||||
type NumCount struct {
|
||||
num int
|
||||
count int
|
||||
}
|
||||
|
||||
//思路说明:如果在一个数组中,有数字超过数组长度的1/3,那么对于整个数组来说,最多有两个数字能够超过1/3
|
||||
//多数投票升级版:
|
||||
//
|
||||
//超过n/3的数最多只能有两个。先选出两个候选人A,B。 遍历数组,分三种情况:
|
||||
// 1.如果投A(当前元素等于A),则A的票数++;
|
||||
// 2.如果投B(当前元素等于B),B的票数++;
|
||||
// 3.如果A,B都不投(即当前与A,B都不相等),那么检查此时A或B的票数是否减为0:
|
||||
// 3.1 如果为0,则当前元素成为新的候选人;
|
||||
// 3.2 如果A,B两个人的票数都不为0,那么A,B两个候选人的票数均减一;
|
||||
//遍历结束后选出了两个候选人,但是这两个候选人是否满足>n/3,还需要再遍历一遍数组,找出两个候选人的具体票数。
|
||||
|
||||
func majorityElement2(nums []int) []int {
|
||||
result := make([]int, 0)
|
||||
var numCount1, numCount2 NumCount
|
||||
for _, num := range nums {
|
||||
switch num {
|
||||
case numCount1.num:
|
||||
numCount1.count++
|
||||
continue
|
||||
case numCount2.num:
|
||||
numCount2.count++
|
||||
default:
|
||||
if numCount1.count == 0 {
|
||||
numCount1.num = num
|
||||
numCount1.count++
|
||||
continue
|
||||
}
|
||||
|
||||
if numCount2.count == 0 {
|
||||
numCount2.num = num
|
||||
numCount2.count++
|
||||
continue
|
||||
}
|
||||
|
||||
numCount1.count--
|
||||
numCount2.count--
|
||||
}
|
||||
}
|
||||
|
||||
//遍历结束后选出了两个候选人,但是这两个候选人是否满足>n/3,还需要再遍历一遍数组,找出两个候选人的具体票数。
|
||||
var count1, count2 int
|
||||
for _, num := range nums {
|
||||
if numCount1.num == num {
|
||||
count1++
|
||||
}
|
||||
if numCount2.num == num && numCount1.num != numCount2.num {
|
||||
count2++
|
||||
}
|
||||
}
|
||||
|
||||
if count1 > len(nums)/3 {
|
||||
result = append(result, numCount1.num)
|
||||
}
|
||||
if count2 > len(nums)/3 {
|
||||
result = append(result, numCount2.num)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func TestMajorityElement2(t *testing.T) {
|
||||
fmt.Println(majorityElement2([]int{3, 2, 3}))
|
||||
fmt.Println(majorityElement2([]int{1, 1, 1, 3, 3, 2, 2, 2}))
|
||||
fmt.Println(majorityElement2([]int{1}))
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/12/24 9:30
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package SingleNum
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type SingleNumber2 struct{}
|
||||
|
||||
func (SingleNumber2) Description(string) string {
|
||||
return `
|
||||
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
|
||||
|
||||
说明:
|
||||
|
||||
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
|
||||
|
||||
示例 1:
|
||||
|
||||
输入: [2,2,3,2]
|
||||
输出: 3
|
||||
示例2:
|
||||
|
||||
输入: [0,1,0,1,0,1,99]
|
||||
输出: 99
|
||||
`
|
||||
}
|
||||
|
||||
//思路分析:最常规的方法是使用map统计或者是set去重,这边记录另外两种解法
|
||||
|
||||
//如果所有数字都出现了 3 次,那么每一列的 1 的个数就一定是 3 的倍数。之所以有的列不是 3 的倍数,就是因为只出现了 1 次的数贡献出了 1。所以所有不是 3 的倍数的列写 1,其他列写 0 ,就找到了这个出现 1 次的数。
|
||||
//go这边要取64位,因为我的机器是64位的,如果我取32位就没办法得到正确的答案
|
||||
func singleNumber2(nums []int) int {
|
||||
var result int
|
||||
//遍历每一位。这边只考虑64位的情况
|
||||
for i := 0; i < 64; i++ {
|
||||
var res int
|
||||
//遍历每一个数字
|
||||
for _, num := range nums {
|
||||
//对每个数字进行移位,然后 & 上1就可以得到移位后的最后一位是否为1的结果。进行该位置的1的个数的统计
|
||||
res += (num >> i) & 1
|
||||
}
|
||||
//该位置的1的个数%3,余数就是该位置是否为1的判断,然后再移动原来的位置,通过 | 来得到最终的结果
|
||||
result = result | ((res % 3) << i)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
//思路分析:
|
||||
//func singleNumber3(nums []int) int {
|
||||
//
|
||||
//}
|
||||
|
||||
func TestSingleNumber2(t *testing.T) {
|
||||
fmt.Println(singleNumber2([]int{2, 2, 3, 2}))
|
||||
fmt.Println(singleNumber2([]int{0, 1, 0, 1, 0, 1, 99}))
|
||||
fmt.Println(singleNumber2([]int{-2, -2, 1, 1, 4, 1, 4, 4, -4, -2}))
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/12/24 14:56
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package SingleNum
|
||||
|
||||
import "testing"
|
||||
|
||||
type SimpleNumber3 struct{}
|
||||
|
||||
func (SimpleNumber3) Description(string) string {
|
||||
return `
|
||||
给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。
|
||||
|
||||
示例 :
|
||||
|
||||
输入: [1,2,1,3,2,5]
|
||||
输出: [3,5]
|
||||
注意:
|
||||
|
||||
结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。
|
||||
你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?
|
||||
`
|
||||
|
||||
}
|
||||
|
||||
func singleNumber3(nums []int) int {
|
||||
//todo 待解答:https://leetcode-cn.com/problems/single-number-iii/solution/zhi-chu-xian-yi-ci-de-shu-zi-iii-by-leetcode/
|
||||
//todo https://leetcode-cn.com/problems/single-number-iii/solution/java-yi-huo-100-yao-shi-kan-bu-dong-wo-jiu-qu-chu-/
|
||||
return 1
|
||||
}
|
||||
|
||||
func TestSimpleNum3(t *testing.T) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/12/24 9:24
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package SingleNum
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type SingleNumber struct{}
|
||||
|
||||
func (SingleNumber) Description(string) string {
|
||||
return `
|
||||
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
|
||||
|
||||
说明:
|
||||
|
||||
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
|
||||
|
||||
示例 1:
|
||||
|
||||
输入: [2,2,1]
|
||||
输出: 1
|
||||
示例 2:
|
||||
|
||||
输入: [4,1,2,1,2]
|
||||
输出: 4
|
||||
`
|
||||
}
|
||||
|
||||
func singleNumber(nums []int) int {
|
||||
var result int
|
||||
for _, num := range nums {
|
||||
result = result ^ num
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func TestSingleNumber(t *testing.T) {
|
||||
fmt.Println(singleNumber([]int{2, 2, 1}))
|
||||
fmt.Println(singleNumber([]int{4, 1, 2, 1, 2}))
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* @Author : huangzj
|
||||
* @Time : 2020/12/21 11:18
|
||||
* @Description:
|
||||
*/
|
||||
|
||||
package simple
|
||||
|
||||
import "testing"
|
||||
|
||||
type TwoNum struct{}
|
||||
|
||||
func (TwoNum) Description(string) string {
|
||||
return `
|
||||
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
|
||||
|
||||
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
|
||||
|
||||
示例:
|
||||
|
||||
给定 nums = [2, 7, 11, 15], target = 9
|
||||
|
||||
因为 nums[0] + nums[1] = 2 + 7 = 9
|
||||
所以返回 [0, 1]
|
||||
|
||||
`
|
||||
}
|
||||
|
||||
//思路分析:map用来缓存比target小的数据, 比如说A + B =target.先遍历到A,则存储B -> A的下标,当找到B的时候,就可以把A的下标一起返回
|
||||
func twoSum(nums []int, target int) []int {
|
||||
deal := make(map[int]int, 0)
|
||||
for i, row := range nums {
|
||||
if index, ok := deal[row]; ok {
|
||||
return []int{index, i}
|
||||
}
|
||||
deal[target-row] = i
|
||||
}
|
||||
|
||||
return []int{}
|
||||
}
|
||||
|
||||
func TestTwoSum(t *testing.T) {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user