From 0a2e5e71a6810abb27fdb63aa09c52fd327d3cb8 Mon Sep 17 00:00:00 2001 From: Huangzj Date: Fri, 25 Dec 2020 11:49:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(Go-StudyExample):2020/12/25=EF=BC=9A?= =?UTF-8?q?=E6=96=B0=E5=A2=9Eleetcode=E9=83=A8=E5=88=86=E4=B9=A0=E9=A2=98?= =?UTF-8?q?=EF=BC=88=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84=E3=80=81=E4=BA=8C?= =?UTF-8?q?=E8=BF=9B=E5=88=B6=E7=9B=B8=E5=85=B3=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- leetCode/simple/Doc.go | 11 ++ .../simple/FindDisappearedNumbers_test.go | 78 +++++++++++++ leetCode/simple/GroupAnagrams_test.go | 66 +++++++++++ leetCode/simple/IsAnagram_test.go | 63 ++++++++++ leetCode/simple/LongestCommonPrefix_test.go | 74 ++++++++++++ .../MajorityElement/MajorityElement1_test.go | 54 +++++++++ .../MajorityElement/MajorityElement2_test.go | 109 ++++++++++++++++++ .../simple/SingleNum/SingleNumber2_test.go | 64 ++++++++++ .../simple/SingleNum/SingleNumber3_test.go | 37 ++++++ .../simple/SingleNum/SingleNumber_test.go | 46 ++++++++ leetCode/simple/TwoSum_test.go | 44 +++++++ readme.md | 2 + 12 files changed, 648 insertions(+) create mode 100644 leetCode/simple/Doc.go create mode 100644 leetCode/simple/FindDisappearedNumbers_test.go create mode 100644 leetCode/simple/GroupAnagrams_test.go create mode 100644 leetCode/simple/IsAnagram_test.go create mode 100644 leetCode/simple/LongestCommonPrefix_test.go create mode 100644 leetCode/simple/MajorityElement/MajorityElement1_test.go create mode 100644 leetCode/simple/MajorityElement/MajorityElement2_test.go create mode 100644 leetCode/simple/SingleNum/SingleNumber2_test.go create mode 100644 leetCode/simple/SingleNum/SingleNumber3_test.go create mode 100644 leetCode/simple/SingleNum/SingleNumber_test.go create mode 100644 leetCode/simple/TwoSum_test.go diff --git a/leetCode/simple/Doc.go b/leetCode/simple/Doc.go new file mode 100644 index 0000000..bfabd76 --- /dev/null +++ b/leetCode/simple/Doc.go @@ -0,0 +1,11 @@ +/* + * @Author : huangzj + * @Time : 2020/12/21 22:26 + * @Description: + */ + +package simple + +type Doc interface { + Description(string) string +} diff --git a/leetCode/simple/FindDisappearedNumbers_test.go b/leetCode/simple/FindDisappearedNumbers_test.go new file mode 100644 index 0000000..f466543 --- /dev/null +++ b/leetCode/simple/FindDisappearedNumbers_test.go @@ -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})) +} diff --git a/leetCode/simple/GroupAnagrams_test.go b/leetCode/simple/GroupAnagrams_test.go new file mode 100644 index 0000000..8815f0e --- /dev/null +++ b/leetCode/simple/GroupAnagrams_test.go @@ -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) + } +} diff --git a/leetCode/simple/IsAnagram_test.go b/leetCode/simple/IsAnagram_test.go new file mode 100644 index 0000000..82c7520 --- /dev/null +++ b/leetCode/simple/IsAnagram_test.go @@ -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")) +} diff --git a/leetCode/simple/LongestCommonPrefix_test.go b/leetCode/simple/LongestCommonPrefix_test.go new file mode 100644 index 0000000..8765f9e --- /dev/null +++ b/leetCode/simple/LongestCommonPrefix_test.go @@ -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"})) +} diff --git a/leetCode/simple/MajorityElement/MajorityElement1_test.go b/leetCode/simple/MajorityElement/MajorityElement1_test.go new file mode 100644 index 0000000..d2be8de --- /dev/null +++ b/leetCode/simple/MajorityElement/MajorityElement1_test.go @@ -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})) +} diff --git a/leetCode/simple/MajorityElement/MajorityElement2_test.go b/leetCode/simple/MajorityElement/MajorityElement2_test.go new file mode 100644 index 0000000..f167f5b --- /dev/null +++ b/leetCode/simple/MajorityElement/MajorityElement2_test.go @@ -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})) +} diff --git a/leetCode/simple/SingleNum/SingleNumber2_test.go b/leetCode/simple/SingleNum/SingleNumber2_test.go new file mode 100644 index 0000000..57f399b --- /dev/null +++ b/leetCode/simple/SingleNum/SingleNumber2_test.go @@ -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})) +} diff --git a/leetCode/simple/SingleNum/SingleNumber3_test.go b/leetCode/simple/SingleNum/SingleNumber3_test.go new file mode 100644 index 0000000..b912ef3 --- /dev/null +++ b/leetCode/simple/SingleNum/SingleNumber3_test.go @@ -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) { + +} diff --git a/leetCode/simple/SingleNum/SingleNumber_test.go b/leetCode/simple/SingleNum/SingleNumber_test.go new file mode 100644 index 0000000..53468bc --- /dev/null +++ b/leetCode/simple/SingleNum/SingleNumber_test.go @@ -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})) +} diff --git a/leetCode/simple/TwoSum_test.go b/leetCode/simple/TwoSum_test.go new file mode 100644 index 0000000..1bfd7f1 --- /dev/null +++ b/leetCode/simple/TwoSum_test.go @@ -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) { + +} diff --git a/readme.md b/readme.md index 8c3a742..d1b7987 100644 --- a/readme.md +++ b/readme.md @@ -29,6 +29,8 @@ json与struct之间转换处理工具使用示例 2020/12/17:新增sdk包Logger的使用示例 +2020/12/25:新增leetcode部分习题(数据结构、二进制相关) + # mod vendor模式加载包 通过go mod的方式加载的github上面的包会有报红的问题,但是包本身是可以运行的,这样就是会有一个问题,如果你想要点击去看方法的内容,没办法做到