diff --git a/.vscode/settings.json b/.vscode/settings.json index 661c044..9c1b310 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,10 +5,5 @@ "markdown": true, "scminput": false }, - "editor.wordWrap": "wordWrapColumn", - "gopls": { - "analyses": { - "unusedfunc": false - } - } + "editor.wordWrap": "wordWrapColumn" } diff --git a/go/add_binary.go b/go/add_binary.go index 0752952..9ae2bbd 100644 --- a/go/add_binary.go +++ b/go/add_binary.go @@ -10,22 +10,22 @@ import ( func addBinary(a string, b string) string { var reversed strings.Builder carry := 0 - for i := 1; ; i++ { - if len(a)-i < 0 && len(b)-i < 0 && carry == 0 { - break - } + for i := 1; i <= len(a) || i <= len(b); i++ { bitA, bitB := 0, 0 - if len(a)-i >= 0 { + if i <= len(a) { bitA, _ = strconv.Atoi(string(a[len(a)-i])) } - if len(b)-i >= 0 { + if i <= len(b) { bitB, _ = strconv.Atoi(string(b[len(b)-i])) } sum := bitA + bitB + carry - reversed.WriteString(strconv.Itoa(sum % 2)) carry = sum / 2 + reversed.WriteString(strconv.Itoa(sum % 2)) + } + if carry == 1 { + reversed.WriteByte('1') } - added := []rune(reversed.String()) - slices.Reverse(added) - return string(added) + result := []rune(reversed.String()) + slices.Reverse(result) + return string(result) } diff --git a/go/add_two_numbers.go b/go/add_two_numbers.go index fdf99bd..ce0e5dd 100644 --- a/go/add_two_numbers.go +++ b/go/add_two_numbers.go @@ -1,46 +1,23 @@ //lint:file-ignore U1000 Ignore all unused code package main -// dummyを使うことで最後に値0を持つノードを作らずに済む -// 単純にl1とl2の数を求めて足し算する方法だと、64個以上のノード数を持つリスト同士の足し算ができない -func addTwoNumbersIteratice(l1 *ListNode, l2 *ListNode) *ListNode { +func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode { dummy := new(ListNode) - nodeSum, node1, node2 := dummy, l1, l2 + node := dummy carry := 0 - for node1 != nil || node2 != nil || carry != 0 { + for l1 != nil || l2 != nil || carry != 0 { sum := carry - if node1 != nil { - sum += node1.Val - node1 = node1.Next + if l1 != nil { + sum += l1.Val + l1 = l1.Next } - if node2 != nil { - sum += node2.Val - node2 = node2.Next + if l2 != nil { + sum += l2.Val + l2 = l2.Next } - nodeSum.Next = &ListNode{sum % 10, nil} - nodeSum = nodeSum.Next + node.Next = &ListNode{Val: sum % 10} carry = sum / 10 + node = node.Next } return dummy.Next } - -func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode { - return addTwoDigitsWithCarry(l1, l2, 0) -} - -func addTwoDigitsWithCarry(node1 *ListNode, node2 *ListNode, carry int) *ListNode { - if node1 == nil && node2 == nil && carry == 0 { - return nil - } - sum := carry - if node1 != nil { - sum += node1.Val - node1 = node1.Next - } - if node2 != nil { - sum += node2.Val - node2 = node2.Next - } - next := addTwoDigitsWithCarry(node1, node2, sum/10) - return &ListNode{sum % 10, next} -} diff --git a/go/backspace_string_compare.go b/go/backspace_string_compare.go index 2b8f975..e70e44d 100644 --- a/go/backspace_string_compare.go +++ b/go/backspace_string_compare.go @@ -1,14 +1,12 @@ //lint:file-ignore U1000 Ignore all unused code package main -import "strings" - func backspaceCompareStack(s string, t string) bool { return typedText(s) == typedText(t) } func typedText(s string) string { - stack := make([]rune, 0, len(s)) + var stack []rune for _, r := range s { if r == '#' { if len(stack) > 0 { @@ -21,44 +19,69 @@ func typedText(s string) string { return string(stack) } -func backspaceCompareReverse(s string, t string) bool { - return reversedText(s) == reversedText(t) +func backspaceCompareReverse1(s string, t string) bool { + runeS, runeT := []rune(s), []rune(t) + i, j := len(runeS)-1, len(runeT)-1 + for i >= 0 || j >= 0 { + i, j = nextIndex(runeS, i), nextIndex(runeT, j) + if i >= 0 && j >= 0 && runeS[i] == runeT[j] { + i-- + j-- + continue + } + if i >= 0 || j >= 0 { + return false + } + } + return true } -func reversedText(s string) string { - var text strings.Builder - skip := 0 - for i := len(s) - 1; i >= 0; i-- { - if s[i] == '#' { - skip++ - } else if skip > 0 { - skip-- +func nextIndex(runeS []rune, index int) int { + count := 0 + for { + if index >= 0 && runeS[index] == '#' { + count++ + } else if count > 0 { + count-- } else { - text.WriteByte(s[i]) + break } + index-- } - return text.String() + return index } -/* -goroutine -*/ -func backspaceCompareStackGoroutine(s string, t string) bool { - chS := make(chan string, 1) - chT := make(chan string, 1) - go func() { chS <- typedText(s) }() - go func() { chT <- typedText(t) }() - sText := <-chS - tText := <-chT - return sText == tText -} - -func backspaceCompareReverseGoroutine(s string, t string) bool { - chS := make(chan string, 1) - chT := make(chan string, 1) - go func() { chS <- reversedText(s) }() - go func() { chT <- reversedText(t) }() - sText := <-chS - tText := <-chT - return sText == tText +func backspaceCompareReverse2(s string, t string) bool { + runeS, runeT := []rune(s), []rune(t) + i, j := len(runeS)-1, len(runeT)-1 + sCount, tCount := 0, 0 + for i >= 0 || j >= 0 { + if i >= 0 && runeS[i] == '#' { + sCount++ + i-- + continue + } + if j >= 0 && runeT[j] == '#' { + tCount++ + j-- + continue + } + if sCount > 0 { + sCount-- + i-- + continue + } + if tCount > 0 { + tCount-- + j-- + continue + } + if i >= 0 && j >= 0 && runeS[i] == runeT[j] { + i-- + j-- + continue + } + return false + } + return true } diff --git a/go/combination_sum.go b/go/combination_sum.go index a5b8b95..65c3316 100644 --- a/go/combination_sum.go +++ b/go/combination_sum.go @@ -1,73 +1,67 @@ //lint:file-ignore U1000 Ignore all unused code package main -import "slices" - -// 時間計算量: 両者とも最悪で指数時間かかるが、バックトラッキングの方が剪定の効果があり実行時間は短くなりやすい。 -// 空間計算量: DPはすべての部分和の組み合わせを記録するためメモリ使用量が多くなる。バックトラッキングは再帰の深さ分だけを保持するためメモリ使用量は少なくなる。 - -func combinationSumBacktrackingRecursion(candidates []int, target int) [][]int { - var combinations [][]int - var combination []int - var generate func(int, int) - generate = func(sum, currentIndex int) { - if sum > target { - return - } - if sum == target { - combinations = append(combinations, slices.Clone(combination)) - return - } - for i := currentIndex; i < len(candidates); i++ { - combination = append(combination, candidates[i]) - generate(sum+candidates[i], i) - combination = combination[:len(combination)-1] +func combinationSumDP(candidates []int, target int) [][]int { + combinationsGroups := make([][][]int, target+1) + combinationsGroups[0] = [][]int{{}} + for _, candidate := range candidates { + for i := candidate; i <= target; i++ { + for _, combination := range combinationsGroups[i-candidate] { + newCombination := append([]int{}, combination...) + newCombination = append(newCombination, candidate) + combinationsGroups[i] = append(combinationsGroups[i], newCombination) + } } } - generate(0, 0) - return combinations -} - -type combinationFrame struct { - combination []int - sum int - currentIndex int + return combinationsGroups[target] } func combinationSumBacktrackingIterative(candidates []int, target int) [][]int { - var combinations [][]int - stack := []combinationFrame{{[]int{}, 0, 0}} + combinations := [][]int{} + type state struct { + combination []int + sum int + index int + } + stack := []state{{[]int{}, 0, 0}} for len(stack) > 0 { - f := stack[len(stack)-1] + current := stack[len(stack)-1] stack = stack[:len(stack)-1] - if f.sum > target { - continue - } - if f.sum == target { - combinations = append(combinations, f.combination) + if current.sum == target { + combinations = append(combinations, current.combination) continue } - for i := f.currentIndex; i < len(candidates); i++ { - newCombination := append(slices.Clone(f.combination), candidates[i]) - stack = append(stack, combinationFrame{newCombination, f.sum + candidates[i], i}) + for i := current.index; i < len(candidates); i++ { + newSum := current.sum + candidates[i] + if newSum > target { + continue + } + newCombination := append([]int{}, current.combination...) + newCombination = append(newCombination, candidates[i]) + stack = append(stack, state{newCombination, newSum, i}) } } return combinations } -func combinationSumDP(candidates []int, target int) [][]int { - memo := make([][][]int, target+1) - memo[0] = [][]int{{}} - for _, candidate := range candidates { - for sum, combinations := range memo { - if sum+candidate > target { - break - } - for _, combination := range combinations { - newCombination := append(slices.Clone(combination), candidate) - memo[sum+candidate] = append(memo[sum+candidate], newCombination) - } +func combinationSumBacktrackingRecursion(candidates []int, target int) [][]int { + var combinations [][]int + var combination []int + var generateCombinations func(int, int) + generateCombinations = func(currentIndex int, sum int) { + if sum == target { + combinations = append(combinations, append([]int{}, combination...)) + return + } + if sum > target { + return + } + for i := currentIndex; i < len(candidates); i++ { + combination = append(combination, candidates[i]) + generateCombinations(i, sum+candidates[i]) + combination = combination[:len(combination)-1] } } - return memo[target] + generateCombinations(0, 0) + return combinations } diff --git a/go/convert_sorted_array_to_binary_search_tree.go b/go/convert_sorted_array_to_binary_search_tree.go index b81b026..28ea874 100644 --- a/go/convert_sorted_array_to_binary_search_tree.go +++ b/go/convert_sorted_array_to_binary_search_tree.go @@ -1,142 +1,15 @@ //lint:file-ignore U1000 Ignore all unused code package main -import "container/list" - func sortedArrayToBST(nums []int) *TreeNode { if len(nums) == 0 { return nil } - midIndex := len(nums) / 2 - return &TreeNode{ - Val: nums[midIndex], - Left: sortedArrayToBST(nums[:midIndex]), - Right: sortedArrayToBST(nums[midIndex+1:]), - } -} - -func sortedArrayToBSTClosed(nums []int) *TreeNode { - if len(nums) == 0 { - return nil - } - return sortedArrayToBSTClosedHelper(nums, 0, len(nums)-1) -} -func sortedArrayToBSTClosedHelper(nums []int, left, right int) *TreeNode { - if left > right { - return nil - } - mid := left + (right-left)/2 - return &TreeNode{ - Val: nums[mid], - Left: sortedArrayToBSTClosedHelper(nums, left, mid-1), - Right: sortedArrayToBSTClosedHelper(nums, mid+1, right), - } -} - -func sortedArrayToBSTHalfOpen(nums []int) *TreeNode { - if len(nums) == 0 { - return nil - } - return sortedArrayToBSTHalfOpenHelper(nums, 0, len(nums)) -} - -func sortedArrayToBSTHalfOpenHelper(nums []int, left, right int) *TreeNode { - if left == right { - return nil - } - mid := left + (right-left)/2 + mid := len(nums) / 2 return &TreeNode{ Val: nums[mid], - Left: sortedArrayToBSTHalfOpenHelper(nums, left, mid), - Right: sortedArrayToBSTHalfOpenHelper(nums, mid+1, right), - } -} - -type bstElement struct { - root *TreeNode - left []int - right []int -} - -func sortedArrayToBSTDFS(nums []int) *TreeNode { - if len(nums) == 0 { - return nil - } - midIndex := len(nums) / 2 - root := &TreeNode{Val: nums[midIndex]} - stack := []bstElement{{root, nums[:midIndex], nums[midIndex+1:]}} - for len(stack) > 0 { - e := stack[len(stack)-1] - stack = stack[:len(stack)-1] - if len(e.left) > 0 { - leftMid := len(e.left) / 2 - e.root.Left = &TreeNode{Val: e.left[leftMid]} - stack = append(stack, bstElement{ - e.root.Left, e.left[:leftMid], e.left[leftMid+1:], - }) - } - if len(e.right) > 0 { - rightMid := len(e.right) / 2 - e.root.Right = &TreeNode{Val: e.right[rightMid]} - stack = append(stack, bstElement{ - e.root.Right, e.right[:rightMid], e.right[rightMid+1:], - }) - } - } - return root -} - -func sortedArrayToBSTBFS(nums []int) *TreeNode { - if len(nums) == 0 { - return nil - } - midIndex := len(nums) / 2 - root := &TreeNode{Val: nums[midIndex]} - queue := list.New() - queue.PushBack(bstElement{root, nums[:midIndex], nums[midIndex+1:]}) - for queue.Len() > 0 { - e := queue.Remove(queue.Front()).(bstElement) - if len(e.left) > 0 { - leftMid := len(e.left) / 2 - e.root.Left = &TreeNode{Val: e.left[leftMid]} - queue.PushBack(bstElement{ - e.root.Left, e.left[:leftMid], e.left[leftMid+1:], - }) - } - if len(e.right) > 0 { - rightMid := len(e.right) / 2 - e.root.Right = &TreeNode{Val: e.right[rightMid]} - queue.PushBack(bstElement{ - e.root.Right, e.right[:rightMid], e.right[rightMid+1:], - }) - } - } - return root -} - -func sortedArrayToBSTInorder(nums []int) *TreeNode { - root := dummyCompleteBinaryTree(0, len(nums)) - setValueInorder(root, nums) - return root -} - -func dummyCompleteBinaryTree(index, length int) *TreeNode { - if index >= length { - return nil - } - node := &TreeNode{} - node.Left = dummyCompleteBinaryTree(index*2+1, length) - node.Right = dummyCompleteBinaryTree(index*2+2, length) - return node -} - -func setValueInorder(root *TreeNode, nums []int) []int { - if root == nil || len(nums) == 0 { - return nums + Left: sortedArrayToBST(nums[:mid]), + Right: sortedArrayToBST(nums[mid+1:]), } - nums = setValueInorder(root.Left, nums) - root.Val = nums[0] - nums = setValueInorder(root.Right, nums[1:]) - return nums } diff --git a/go/first_unique_character_in_a_string.go b/go/first_unique_character_in_a_string.go index bb7ef1b..12f238c 100644 --- a/go/first_unique_character_in_a_string.go +++ b/go/first_unique_character_in_a_string.go @@ -2,12 +2,12 @@ package main func firstUniqChar(s string) int { - frequencies := make(map[rune]int) + frequency := make(map[rune]int) for _, r := range s { - frequencies[r]++ + frequency[r]++ } for i, r := range s { - if frequencies[r] == 1 { + if frequency[r] == 1 { return i } } @@ -15,12 +15,12 @@ func firstUniqChar(s string) int { } func firstUniqChar2(s string) int { - var frequencies [26]int + var frequency [26]int for _, r := range s { - frequencies[r-'a']++ + frequency[r-'a']++ } for i, r := range s { - if frequencies[r-'a'] == 1 { + if frequency[r-'a'] == 1 { return i } } diff --git a/go/generate_parentheses.go b/go/generate_parentheses.go index 83448cb..5bb6813 100644 --- a/go/generate_parentheses.go +++ b/go/generate_parentheses.go @@ -1,56 +1,55 @@ //lint:file-ignore U1000 Ignore all unused code package main -import "slices" - -func generateParenthesisRecursive(n int) []string { - var combinations []string - combination := make([]rune, 0, n*2) - var generate func(int, int) - generate = func(openNum, closeNum int) { - if openNum == n && closeNum == n { - combinations = append(combinations, string(combination)) - return +func generateParenthesisIterative(n int) []string { + var parentheses []string + type state struct { + parenthesis []byte + open int + closed int + } + stack := []state{{[]byte{}, 0, 0}} + for len(stack) > 0 { + current := stack[len(stack)-1] + stack = stack[:len(stack)-1] + if current.open == n && current.closed == n { + parentheses = append(parentheses, string(current.parenthesis)) + continue } - if openNum < n { - combination = append(combination, '(') - generate(openNum+1, closeNum) - combination = combination[:len(combination)-1] + if current.open < n { + newParenthesis := append([]byte{}, current.parenthesis...) + newParenthesis = append(newParenthesis, '(') + stack = append(stack, state{newParenthesis, current.open + 1, current.closed}) } - if closeNum < openNum { - combination = append(combination, ')') - generate(openNum, closeNum+1) - combination = combination[:len(combination)-1] + if current.open > current.closed { + newParenthesis := append([]byte{}, current.parenthesis...) + newParenthesis = append(newParenthesis, ')') + stack = append(stack, state{newParenthesis, current.open, current.closed + 1}) } } - generate(0, 0) - return combinations + return parentheses } -type frame struct { - combination []rune - openNum int - closeNum int -} - -func generateParenthesisIterative(n int) []string { - var combinations []string - stack := []frame{{[]rune{}, 0, 0}} - for len(stack) > 0 { - f := stack[len(stack)-1] - stack = stack[:len(stack)-1] - if f.openNum == n && f.closeNum == n { - combinations = append(combinations, string(f.combination)) - continue +func generateParenthesisRecursive(n int) []string { + var parentheses []string + parenthesis := make([]byte, 0, n*2) + var generate func(int, int) + generate = func(open int, closed int) { + if open == n && closed == n { + parentheses = append(parentheses, string(parenthesis)) + return } - if f.openNum < n { - newCombination := append(slices.Clone(f.combination), '(') - stack = append(stack, frame{newCombination, f.openNum + 1, f.closeNum}) + if open < n { + parenthesis = append(parenthesis, '(') + generate(open+1, closed) + parenthesis = parenthesis[:len(parenthesis)-1] } - if f.closeNum < f.openNum { - newCombination := append(slices.Clone(f.combination), ')') - stack = append(stack, frame{newCombination, f.openNum, f.closeNum + 1}) + if open > closed { + parenthesis = append(parenthesis, ')') + generate(open, closed+1) + parenthesis = parenthesis[:len(parenthesis)-1] } } - return combinations + generate(0, 0) + return parentheses } diff --git a/go/is_subsequence.go b/go/is_subsequence.go index 211bb09..306c2cb 100644 --- a/go/is_subsequence.go +++ b/go/is_subsequence.go @@ -2,23 +2,12 @@ package main func isSubsequence(s string, t string) bool { - sIndex, tIndex := 0, 0 - for sIndex < len(s) && tIndex < len(t) { - if s[sIndex] == t[tIndex] { - sIndex++ + i, j := 0, 0 + for i < len(s) && j < len(t) { + if s[i] == t[j] { + i++ } - tIndex++ + j++ } - return sIndex == len(s) -} - -func isSubsequence2(s string, t string) bool { - sIndex := 0 - runeS := []rune(s) - for _, r := range t { - if sIndex < len(runeS) && r == runeS[sIndex] { - sIndex++ - } - } - return sIndex == len(runeS) + return i == len(s) } diff --git a/go/longest_common_prefix.go b/go/longest_common_prefix.go index eeec35c..c87dd75 100644 --- a/go/longest_common_prefix.go +++ b/go/longest_common_prefix.go @@ -8,61 +8,66 @@ import ( func longestCommonPrefix(strs []string) string { var prefix strings.Builder for i := 0; ; i++ { - var currentChar byte - for j, s := range strs { - if i >= len(s) { + var curr rune + for _, word := range strs { + if i >= len(word) { return prefix.String() } - if j == 0 { - currentChar = s[i] + if curr == 0 { + curr = rune(word[i]) + continue } - if currentChar != s[i] { + if rune(word[i]) != curr { return prefix.String() } } - prefix.WriteByte(currentChar) + prefix.WriteRune(curr) } } /* Trie */ -type trieNode struct { - children map[rune]*trieNode +type Trie struct { + root *Node +} + +type Node struct { + children map[rune]*Node isWordEnd bool } -func newTrieNode() *trieNode { - return &trieNode{make(map[rune]*trieNode), false} +func NewTrie() *Trie { + return &Trie{root: &Node{children: make(map[rune]*Node)}} } -func (t *trieNode) insert(s string) { - node := t - for _, r := range s { +func (t *Trie) Insert(word string) { + node := t.root + for _, r := range word { if _, ok := node.children[r]; !ok { - node.children[r] = newTrieNode() + node.children[r] = &Node{children: make(map[rune]*Node)} } node = node.children[r] } node.isWordEnd = true } -func (t *trieNode) commonPrefix() string { +func (t *Trie) Prefix() string { var prefix strings.Builder - node := t + node := t.root for len(node.children) == 1 && !node.isWordEnd { - for r, next := range node.children { + for r, child := range node.children { prefix.WriteRune(r) - node = next + node = child // ここでnodeをchildで更新してもrangeは評価済みなのでループが続くことはない } } return prefix.String() } func longestCommonPrefixTrie(strs []string) string { - t := newTrieNode() - for _, s := range strs { - t.insert(s) + t := NewTrie() + for _, word := range strs { + t.Insert(word) } - return t.commonPrefix() + return t.Prefix() } diff --git a/go/longest_substring_without_repeating_characters.go b/go/longest_substring_without_repeating_characters.go index 56a0d81..d72e441 100644 --- a/go/longest_substring_without_repeating_characters.go +++ b/go/longest_substring_without_repeating_characters.go @@ -1,17 +1,13 @@ //lint:file-ignore U1000 Ignore all unused code package main -// 重複する文字が含まれていないことが保証されるleft~rightの範囲を作り、 -// rightを1つずつ進めていき、各段階での長さを求め、最大の長さを更新していく。 func lengthOfLongestSubstring(s string) int { - maxLength := 0 - seen := make(map[byte]int, len(s)) - for left, right := 0, 0; right < len(s); right++ { - c := s[right] - if i, ok := seen[c]; ok { - left = max(left, i+1) + maxLength, left, seen := 0, 0, make(map[rune]int) + for right, r := range s { + if lastIndex, ok := seen[r]; ok && lastIndex >= left { + left = lastIndex + 1 } - seen[c] = right + seen[r] = right maxLength = max(maxLength, right-left+1) } return maxLength diff --git a/go/merge_two_sorted_lists.go b/go/merge_two_sorted_lists.go index 27f9c79..d74998c 100644 --- a/go/merge_two_sorted_lists.go +++ b/go/merge_two_sorted_lists.go @@ -1,7 +1,7 @@ //lint:file-ignore U1000 Ignore all unused code package main -func mergeTwoListsIterative(list1 *ListNode, list2 *ListNode) *ListNode { +func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode { dummy := &ListNode{} tail := dummy for list1 != nil && list2 != nil { @@ -20,19 +20,3 @@ func mergeTwoListsIterative(list1 *ListNode, list2 *ListNode) *ListNode { } return dummy.Next } - -func mergeTwoListsRecursive(list1 *ListNode, list2 *ListNode) *ListNode { - if list1 == nil { - return list2 - } - if list2 == nil { - return list1 - } - if list1.Val < list2.Val { - list1.Next = mergeTwoListsRecursive(list1.Next, list2) - return list1 - } else { - list2.Next = mergeTwoListsRecursive(list1, list2.Next) - return list2 - } -} diff --git a/go/missing_number.go b/go/missing_number.go index 9e086cf..f5ea6e3 100644 --- a/go/missing_number.go +++ b/go/missing_number.go @@ -2,10 +2,18 @@ package main func missingNumber(nums []int) int { - expectedTotal := (1 + len(nums)) * len(nums) / 2 - var actualTotal int + sum := 0 for _, n := range nums { - actualTotal += n + sum += n } - return expectedTotal - actualTotal + l := len(nums) + return l*(l+1)/2 - sum +} + +func missingNumber2(nums []int) int { + res := len(nums) + for i, n := range nums { + res += i - n + } + return res } diff --git a/go/move_zeroes.go b/go/move_zeroes.go index f203edc..e4089a3 100644 --- a/go/move_zeroes.go +++ b/go/move_zeroes.go @@ -2,12 +2,10 @@ package main func moveZeroes(nums []int) { - zeroIndex := 0 - for i, n := range nums { - if n == 0 { - continue + for nonZero, cur := 0, 0; cur < len(nums); cur++ { + if nums[cur] != 0 { + nums[nonZero], nums[cur] = nums[cur], nums[nonZero] + nonZero++ } - nums[zeroIndex], nums[i] = nums[i], nums[zeroIndex] - zeroIndex++ } } diff --git a/go/next_permutation.go b/go/next_permutation.go index 817baab..cd62551 100644 --- a/go/next_permutation.go +++ b/go/next_permutation.go @@ -1,27 +1,26 @@ //lint:file-ignore U1000 Ignore all unused code package main -import "sort" - -// [1, 3, 5, 4, 2]という入力があるとき -// 3 < 5なので、3を変える必要がある -// 3より大きい最小の値は4なので、3と4を入れ替えると -// [1, 4, 5, 3, 2]となる -// 3以降の要素を逆順にすると、 -// next permutationの[1, 4, 2, 3, 5]となる。 -// nums[sortedUntil] >= nums[sortedUntil+1]は>ではなく、>=でないと -// [1, 1]などではOut of indexになる func nextPermutation(nums []int) { - sortedUntil := len(nums) - 2 // len(nums) <= 1だとsortedUntil=-1になる点に注意 - for sortedUntil >= 0 && nums[sortedUntil] >= nums[sortedUntil+1] { - sortedUntil-- + if len(nums) < 2 { + return + } + i := len(nums) - 2 + for i >= 0 && nums[i] >= nums[i+1] { + i-- } - if sortedUntil >= 0 { - swapTarget := len(nums) - 1 - for nums[sortedUntil] >= nums[swapTarget] { - swapTarget-- + if i >= 0 { + j := len(nums) - 1 + for nums[j] <= nums[i] { + j-- } - nums[sortedUntil], nums[swapTarget] = nums[swapTarget], nums[sortedUntil] + nums[i], nums[j] = nums[j], nums[i] + } + reverse(nums[i+1:]) +} + +func reverse(nums []int) { + for i, j := 0, len(nums)-1; i < j; i, j = i+1, j-1 { + nums[i], nums[j] = nums[j], nums[i] } - sort.Ints(nums[sortedUntil+1:]) // sortを使うとO(n log n)になるので、別途reverse関数を作るのもあり } diff --git a/go/palindrome_number.go b/go/palindrome_number.go index 4493ec7..a9285c8 100644 --- a/go/palindrome_number.go +++ b/go/palindrome_number.go @@ -1,12 +1,15 @@ //lint:file-ignore U1000 Ignore all unused code package main -func isPalindromeNumbver(x int) bool { - reversed := 0 - tmp := x - for tmp > 0 { - reversed = reversed*10 + tmp%10 - tmp /= 10 +func isPalindromeNumber(x int) bool { + if x < 0 { + return false } - return x == reversed + + original, reversed := x, 0 + for x > 0 { + reversed = reversed*10 + x%10 + x /= 10 + } + return original == reversed } diff --git a/go/permutations.go b/go/permutations.go index d5f3fbc..e3e553d 100644 --- a/go/permutations.go +++ b/go/permutations.go @@ -1,90 +1,81 @@ //lint:file-ignore U1000 Ignore all unused code package main -import ( - "maps" - "slices" - "sort" -) +import "sort" -// 辞書順に生成していく -// [1, 2, 4, 3]の次は[1, 3, 2, 4] -// まず後ろから昇順になっている箇所を探す(2) -// そしてまた後ろから2までで、2よりも大きい一番小さい数を探す(3) -// そしてその2つを入れ替える([1, 3, 4, 2]) -// そしてその後ろの部分を逆順にする([1, 3, 2, 4]) func permuteLexicographically(nums []int) [][]int { - var combinations [][]int - combination := slices.Clone(nums) - sort.Ints(combination) + sort.Ints(nums) + var permutations [][]int for { - combinations = append(combinations, slices.Clone(combination)) - sortedUntil := len(combination) - 2 - for sortedUntil >= 0 && combination[sortedUntil] > combination[sortedUntil+1] { - sortedUntil-- + permutations = append(permutations, append([]int{}, nums...)) + i := len(nums) - 2 + for i >= 0 && nums[i] >= nums[i+1] { + i-- } - if sortedUntil < 0 { + if i < 0 { break } - target := len(combination) - 1 - for combination[sortedUntil] >= combination[target] { - target-- + j := len(nums) - 1 + for nums[j] <= nums[i] { + j-- } - combination[sortedUntil], combination[target] = combination[target], combination[sortedUntil] - sort.Ints(combination[sortedUntil+1:]) + nums[i], nums[j] = nums[j], nums[i] + reverse(nums[i+1:]) } - return combinations + return permutations } -func permuteBacktrackingRecursion(nums []int) [][]int { - var combinations [][]int - combination := make([]int, 0, len(nums)) - seen := make(map[int]struct{}, len(nums)) - var generate func() - generate = func() { - if len(combination) == len(nums) { - combinations = append(combinations, slices.Clone(combination)) - return +func permuteBacktrackingIterative(nums []int) [][]int { + var permutations [][]int + type state struct { + permutation []int + inUse map[int]struct{} + } + stack := []state{{[]int{}, make(map[int]struct{})}} + for len(stack) > 0 { + current := stack[len(stack)-1] + stack = stack[:len(stack)-1] + if len(current.permutation) == len(nums) { + permutations = append(permutations, current.permutation) + continue } for _, n := range nums { - if _, ok := seen[n]; ok { + if _, ok := current.inUse[n]; ok { continue } - combination = append(combination, n) - seen[n] = struct{}{} - generate() - combination = combination[:len(combination)-1] - delete(seen, n) + newPermutation := append([]int{}, current.permutation...) + newPermutation = append(newPermutation, n) + newInUse := make(map[int]struct{}) + for k, v := range current.inUse { + newInUse[k] = v + } + newInUse[n] = struct{}{} + stack = append(stack, state{newPermutation, newInUse}) } } - generate() - return combinations + return permutations } -type permutationFrame struct { - combination []int - seen map[int]struct{} -} - -func permuteBacktrackingIterative(nums []int) [][]int { - var combinations [][]int - stack := []permutationFrame{{make([]int, 0, len(nums)), make(map[int]struct{}, len(nums))}} - for len(stack) > 0 { - f := stack[len(stack)-1] - stack = stack[:len(stack)-1] - if len(f.combination) == len(nums) { - combinations = append(combinations, f.combination) - continue +func permuteBacktrackingRecursion(nums []int) [][]int { + var permutations [][]int + permutation := make([]int, 0, len(nums)) + inUse := make(map[int]struct{}) + var generate func() + generate = func() { + if len(permutation) == len(nums) { + permutations = append(permutations, append([]int{}, permutation...)) + return } for _, n := range nums { - if _, ok := f.seen[n]; ok { - continue + if _, ok := inUse[n]; !ok { + permutation = append(permutation, n) + inUse[n] = struct{}{} + generate() + permutation = permutation[:len(permutation)-1] + delete(inUse, n) } - newCombination := append(slices.Clone(f.combination), n) - newSeen := maps.Clone(f.seen) - newSeen[n] = struct{}{} - stack = append(stack, permutationFrame{newCombination, newSeen}) } } - return combinations + generate() + return permutations } diff --git a/go/search_in_rotated_sorted_array.go b/go/search_in_rotated_sorted_array.go index 345120e..c8dac72 100644 --- a/go/search_in_rotated_sorted_array.go +++ b/go/search_in_rotated_sorted_array.go @@ -1,63 +1,48 @@ //lint:file-ignore U1000 Ignore all unused code package main -// 半閉区画ではleft~right-1が未探索で、rightは常に探索済み -// そのため、for文の条件はleft < rightとなる(left=1, right=2のときmid=1となり、未探索のleftのみが探索の対象となる) -func searchHalfClosed(nums []int, target int) int { - left, right := 0, len(nums) - for left < right { +func searchClosed(nums []int, target int) int { + left, right := 0, len(nums)-1 + for left <= right { mid := left + (right-left)/2 - if nums[mid] == target { + if target == nums[mid] { return mid } - // ここでは左側がソートされているかを判定しているが - // searchClosedとは違ってsearchHalfClosedの場合は - // nums[left] < nums[mid]でも、nums[left] <= nums[mid]でも問題なく動作する - // なぜならsearchHalfClosedでは、nums内にtargetが存在する場合において - // left == mid && nums[mid] != targetになることはないので - // (left==midになるにはlen(nums)==1である必要がある) - // left == midになってもバグらないためである - // 単にたまたまバグらないだけで、意味的にnums[left] <= nums[mid]の方が適切 if nums[left] <= nums[mid] { - if nums[left] <= target && target < nums[mid] { // leftがtargetの可能性もあるので<=とする - right = mid + if nums[left] <= target && target < nums[mid] { + right = mid - 1 } else { left = mid + 1 } } else { - if nums[mid] < target && target <= nums[right-1] { // rightは最初は範囲外なので-1をする。その場合right-1は未探索なので<=とする + if nums[mid] < target && target <= nums[right] { left = mid + 1 } else { - right = mid + right = mid - 1 } } } return -1 } -func searchClosed(nums []int, target int) int { - left, right := 0, len(nums)-1 - for left <= right { +func searchHalfClosed(nums []int, target int) int { + left, right := 0, len(nums) + for left < right { mid := left + (right-left)/2 - if nums[mid] == target { + if target == nums[mid] { return mid } - // ここでは左側がソートされているかを判定しているが - // nums[left] < nums[mid]としてしまうと - // left == midになるとき(例えばnums=[3, 1]) - // 左側がソートされていないと判断されて - // 誤った条件分岐に入ってしまう if nums[left] <= nums[mid] { if nums[left] <= target && target < nums[mid] { - right = mid - 1 + right = mid } else { left = mid + 1 } } else { - if nums[mid] < target && target <= nums[right] { + if nums[mid] < target && target <= nums[right-1] { left = mid + 1 } else { - right = mid - 1 + right = mid } } } diff --git a/go/search_insert_position.go b/go/search_insert_position.go index db36052..9fdfb80 100644 --- a/go/search_insert_position.go +++ b/go/search_insert_position.go @@ -1,12 +1,7 @@ //lint:file-ignore U1000 Ignore all unused code package main -// 長さ1のnums={1}があるとき、 -// left=0, right=1, mid=0になる。 -// target=2のとき、ループを抜ける直前にleft=mid+1されるので、ループを抜けたらleftを返せばいい。 -// target=0のとき、left=0のままなので、ループを抜けたらleftを返せばい(-1を返すわけではないことに注意。targetはleftよりも小さく、leftの左の値よりも大きいわけなので、leftを返せば良い) - -func searchInsertHalfClosed(nums []int, target int) int { +func searchInsert(nums []int, target int) int { left, right := 0, len(nums) for left < right { mid := left + (right-left)/2 @@ -18,19 +13,3 @@ func searchInsertHalfClosed(nums []int, target int) int { } return left } - -func searchInsertClosed(nums []int, target int) int { - left, right := 0, len(nums)-1 - for left <= right { - mid := left + (right-left)/2 - if nums[mid] == target { - return mid - } - if nums[mid] > target { - right = mid - 1 - } else { - left = mid + 1 - } - } - return left -} diff --git a/go/single_number.go b/go/single_number.go index 5365be6..f2eeae5 100644 --- a/go/single_number.go +++ b/go/single_number.go @@ -1,6 +1,12 @@ //lint:file-ignore U1000 Ignore all unused code package main +// nums = [2, 3, 2]のとき +// 1回目のループ:0000 XOR 0010 = 0010 +// 2回目のループ:0010 XOR 0011 = 0001 +// 3回目のループ:0001 XOR 0010 = 0011 +// つまり1つだけ1回だけ出現し、他は全て2回出現するという条件が満たされない時は +// XORを使った方法はうまくいかない(例えば[2, 3]など) func singleNumber(nums []int) int { singleNum := 0 for _, n := range nums { diff --git a/go/string_to_integer_atoi.go b/go/string_to_integer_atoi.go index 05d46f3..0151174 100644 --- a/go/string_to_integer_atoi.go +++ b/go/string_to_integer_atoi.go @@ -1,39 +1,38 @@ //lint:file-ignore U1000 Ignore all unused code package main -import ( - "math" - "strconv" -) +import "math" func myAtoi(s string) int { - currentIndex := 0 - for currentIndex < len(s) && s[currentIndex] == ' ' { - currentIndex++ + const ( + intMax = int(math.MaxInt32) + intMin = int(math.MinInt32) + ) + + i := 0 + for i < len(s) && s[i] == ' ' { + i++ } - signum := 1 - if currentIndex < len(s) { - switch s[currentIndex] { - case '+': - currentIndex++ - case '-': - signum = -1 - currentIndex++ + + sign := 1 + if i < len(s) && (s[i] == '-' || s[i] == '+') { + if s[i] == '-' { + sign = -1 } + i++ } - n := 0 - for i := currentIndex; i < len(s); i++ { - digit, err := strconv.Atoi(string(s[i])) - if err != nil { - break - } - if signum == 1 && (n > math.MaxInt32/10 || digit >= math.MaxInt32-n*10) { - return math.MaxInt32 + + num := 0 + for i < len(s) && '0' <= s[i] && s[i] <= '9' { + digit := int(s[i] - '0') + if sign == 1 && (num > intMax/10 || num == intMax/10 && digit >= intMax%10) { + return intMax } - if signum == -1 && (-n < math.MinInt32/10 || -digit <= math.MinInt32- -n*10) { - return math.MinInt32 + if sign == -1 && (-num < intMin/10 || -num == intMin/10 && -digit <= intMin%10) { + return intMin } - n = n*10 + digit + num = num*10 + digit + i++ } - return n * signum + return sign * num } diff --git a/go/symmetric_tree.go b/go/symmetric_tree.go index b9ce435..42c1cd2 100644 --- a/go/symmetric_tree.go +++ b/go/symmetric_tree.go @@ -3,57 +3,49 @@ package main import "container/list" -func isSymmetric(root *TreeNode) bool { - return areSymmetric(root.Left, root.Right) +func isSymmetricRecursive(root *TreeNode) bool { + if root == nil { + return true + } + return isMirror(root.Left, root.Right) } -func areSymmetric(left, right *TreeNode) bool { - if left == nil && right == nil { +func isMirror(t1, t2 *TreeNode) bool { + if t1 == nil && t2 == nil { return true } - if left == nil || right == nil || left.Val != right.Val { + if t1 == nil || t2 == nil { return false } - return areSymmetric(left.Left, right.Right) && areSymmetric(left.Right, right.Left) + return (t1.Val == t2.Val) && + isMirror(t1.Left, t2.Right) && isMirror(t1.Right, t2.Left) } -type nodePair struct { - left *TreeNode - right *TreeNode -} +func isSymmetricIterative(root *TreeNode) bool { + if root == nil { + return true + } -func isSymmetricBFS(root *TreeNode) bool { queue := list.New() - queue.PushBack(nodePair{root.Left, root.Right}) + queue.PushBack(root.Left) + queue.PushBack(root.Right) + for queue.Len() > 0 { - pair := queue.Remove(queue.Front()).(nodePair) - if pair.left == nil && pair.right == nil { - continue - } - if pair.left == nil || pair.right == nil || pair.left.Val != pair.right.Val { - return false - } - queue.PushBack(nodePair{pair.left.Left, pair.right.Right}) - queue.PushBack(nodePair{pair.left.Right, pair.right.Left}) - } - return true -} + t1 := queue.Remove(queue.Front()).(*TreeNode) + t2 := queue.Remove(queue.Front()).(*TreeNode) -func isSymmetricDFS(root *TreeNode) bool { - stack := []nodePair{{root.Left, root.Right}} - for len(stack) > 0 { - pair := stack[len(stack)-1] - stack = stack[:len(stack)-1] - if pair.left == nil && pair.right == nil { + if t1 == nil && t2 == nil { continue } - if pair.left == nil || pair.right == nil || pair.left.Val != pair.right.Val { + if t1 == nil || t2 == nil || t1.Val != t2.Val { return false } - stack = append(stack, []nodePair{ - {pair.left.Left, pair.right.Right}, - {pair.left.Right, pair.right.Left}, - }...) + + queue.PushBack(t1.Left) + queue.PushBack(t2.Right) + queue.PushBack(t1.Right) + queue.PushBack(t2.Left) } + return true } diff --git a/go/zigzag_conversion.go b/go/zigzag_conversion.go index 1f947a9..ec330f1 100644 --- a/go/zigzag_conversion.go +++ b/go/zigzag_conversion.go @@ -3,27 +3,45 @@ package main import "strings" -// ジグザグの行ごとに作成していき、最後に1つにする -// sの先頭から見ていくので、その文字の行番号さえわかればその行に追加していくだけ func convert(s string, numRows int) string { - if numRows <= 1 { + if numRows == 1 { return s } + rows := make([]strings.Builder, numRows) - blockSize := numRows*2 - 2 + cycleLength := 2*numRows - 2 for i, r := range s { - offset := i % blockSize - var rowIndex int - if offset < numRows { - rowIndex = offset - } else { - rowIndex = blockSize - offset + rowIndex := i % cycleLength + if rowIndex >= numRows { + rowIndex = cycleLength - rowIndex } rows[rowIndex].WriteRune(r) } - var converted strings.Builder + + var oneline strings.Builder for _, row := range rows { - converted.WriteString(row.String()) + oneline.WriteString(row.String()) + } + return oneline.String() +} + +func convert2(s string, numRows int) string { + if numRows == 1 { + return s + } + var oneline strings.Builder + cycleLength := 2*numRows - 2 + for rowIndex := 0; rowIndex < numRows; rowIndex++ { + for i := rowIndex; i < len(s); i += cycleLength { + oneline.WriteByte(s[i]) + if rowIndex == 0 || rowIndex == numRows-1 { + continue + } + diagIndex := i + cycleLength - rowIndex*2 + if diagIndex < len(s) { + oneline.WriteByte(s[diagIndex]) + } + } } - return converted.String() + return oneline.String() } diff --git a/pullrequests/add_two_numbers/step1.go b/pullrequests/add_two_numbers/step1.go deleted file mode 100644 index 6e21428..0000000 --- a/pullrequests/add_two_numbers/step1.go +++ /dev/null @@ -1,48 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package addtwonumbers - -type ListNode struct { - Val int - Next *ListNode -} - -/* -時間:8分35秒 - -方針自体はすぐに決まり、繰り上げと2つの数の桁数の違いに気をつけて、足していけばいいと考えました。末端のノードの値が0になるときの対処に少し悩みました。 -とりあえず動くように書いたのでコードの重複などが多く、こなれていないコードだなと思います。 -*/ -func addTwoNumbers_step1(l1 *ListNode, l2 *ListNode) *ListNode { - dummy := new(ListNode) - dummy.Next = new(ListNode) - dummy.Next.Val = 0 - curr := dummy - for l1 != nil && l2 != nil { - curr = curr.Next - sum := l1.Val + l2.Val + curr.Val - curr.Val = sum % 10 - curr.Next = new(ListNode) - curr.Next.Val = sum / 10 - l1, l2 = l1.Next, l2.Next - } - for l1 != nil { - curr = curr.Next - sum := l1.Val + curr.Val - curr.Val = sum % 10 - curr.Next = new(ListNode) - curr.Next.Val = sum / 10 - l1 = l1.Next - } - for l2 != nil { - curr = curr.Next - sum := l2.Val + curr.Val - curr.Val = sum % 10 - curr.Next = new(ListNode) - curr.Next.Val = sum / 10 - l2 = l2.Next - } - if curr.Next.Val == 0 { - curr.Next = nil - } - return dummy.Next -} diff --git a/pullrequests/add_two_numbers/step2.go b/pullrequests/add_two_numbers/step2.go deleted file mode 100644 index 317506d..0000000 --- a/pullrequests/add_two_numbers/step2.go +++ /dev/null @@ -1,31 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package addtwonumbers - -/* -コードの重複を排除しました。ただまだ無駄な処理が多いです。 -*/ -func addTwoNumbers_step2(l1 *ListNode, l2 *ListNode) *ListNode { - dummy := new(ListNode) - dummy.Next = new(ListNode) - dummy.Next.Val = 0 - curr := dummy - for l1 != nil || l2 != nil { - curr = curr.Next - sum := curr.Val - if l1 != nil { - sum += l1.Val - l1 = l1.Next - } - if l2 != nil { - sum += l2.Val - l2 = l2.Next - } - curr.Val = sum % 10 - curr.Next = new(ListNode) - curr.Next.Val = sum / 10 - } - if curr.Next.Val == 0 { - curr.Next = nil - } - return dummy.Next -} diff --git a/pullrequests/add_two_numbers/step3.go b/pullrequests/add_two_numbers/step3.go deleted file mode 100644 index b1cb8f9..0000000 --- a/pullrequests/add_two_numbers/step3.go +++ /dev/null @@ -1,27 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package addtwonumbers - -/* -carryを導入した方がより明確でシンプルに書けると気づき変更しました。 -carryを導入したことにより、末端に余計なノード(値が0のノード)が発生しなくなりました。 -*/ -func addTwoNumbers_step3(l1 *ListNode, l2 *ListNode) *ListNode { - dummy := new(ListNode) - curr := dummy - carry := 0 - for l1 != nil || l2 != nil || carry != 0 { - sum := carry - if l1 != nil { - sum += l1.Val - l1 = l1.Next - } - if l2 != nil { - sum += l2.Val - l2 = l2.Next - } - curr.Next = &ListNode{Val: sum % 10} - carry = sum / 10 - curr = curr.Next - } - return dummy.Next -} diff --git a/pullrequests/generate_parentheses/step1.go b/pullrequests/generate_parentheses/step1.go deleted file mode 100644 index 63dc348..0000000 --- a/pullrequests/generate_parentheses/step1.go +++ /dev/null @@ -1,34 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package generateparentheses - -/* -初見で解くことができず、他の人の回答を見ながら解く形になってしまいました。 -一応自分でもバックトラッキングをちゃんと理解して自力で下記のコードを書けるようにはなりました。 - -時間計算量と空間計算量はカタラン数になるという認識。 -https://github.com/SuperHotDogCat/coding-interview/pull/7#discussion_r1577988152 -https://github.com/Mike0121/LeetCode/pull/1#discussion_r1577919957 -*/ -func generateParenthesis_step1(n int) []string { - var parentheses []string - var stack []byte - var generate func(int, int) - generate = func(open int, closed int) { - if open == n && closed == n { - parentheses = append(parentheses, string(stack)) - return - } - if open < n { - stack = append(stack, '(') - generate(open+1, closed) - stack = stack[:len(stack)-1] - } - if open > closed { - stack = append(stack, ')') - generate(open, closed+1) - stack = stack[:len(stack)-1] - } - } - generate(0, 0) - return parentheses -} diff --git a/pullrequests/missing_number/step1.go b/pullrequests/missing_number/step1.go deleted file mode 100644 index 67ecd4f..0000000 --- a/pullrequests/missing_number/step1.go +++ /dev/null @@ -1,18 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package template - -/* -レビュワーの方へ: - - このコードは既にGoの標準のフォーマッタで整形済みです。演算子の周りにスペースがあったりなかったりしますが、これはGoのフォーマッタによるもので、優先順位の高い演算子の周りにはスペースが入らず、低い演算子の周りには入るようになっています。https://qiita.com/tchssk/items/77030b4271cd192d0347 -*/ - -/* -方針としては0~len(nums)の和と実際の和の差分を取ればいい。 -*/ -func missingNumberStep1(nums []int) int { - var difference int - for i, n := range nums { - difference += i + 1 - n - } - return difference -} diff --git a/pullrequests/missing_number/step2.go b/pullrequests/missing_number/step2.go deleted file mode 100644 index 1f46968..0000000 --- a/pullrequests/missing_number/step2.go +++ /dev/null @@ -1,18 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package template - -/* -レビュワーの方へ: - - このコードは既にGoの標準のフォーマッタで整形済みです。演算子の周りにスペースがあったりなかったりしますが、これはGoのフォーマッタによるもので、優先順位の高い演算子の周りにはスペースが入らず、低い演算子の周りには入るようになっています。https://qiita.com/tchssk/items/77030b4271cd192d0347 -*/ - -/* -0~len(nums)の和を求めるには算数的に求める方法も取れる。 -*/ -func missingNumberStep2(nums []int) int { - var total int - for _, n := range nums { - total += n - } - return (1+len(nums))*len(nums)/2 - total -} diff --git a/pullrequests/move_zeroes/step1.go b/pullrequests/move_zeroes/step1.go deleted file mode 100644 index 27346fd..0000000 --- a/pullrequests/move_zeroes/step1.go +++ /dev/null @@ -1,27 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package movezeroes - -/* -レビュワーの方へ: - - このコードは既にGoの標準のフォーマッタで整形済みです。演算子の周りにスペースがあったりなかったりしますが、これはGoのフォーマッタによるもので、優先順位の高い演算子の周りにはスペースが入らず、低い演算子の周りには入るようになっています。https://qiita.com/tchssk/items/77030b4271cd192d0347 -*/ - -/* -左側に非ゼロのエリア、右側にゼロのエリアを作れば良い。 -イメージとしてはzeroIndexはゼロのエリアのはじまり(境界)のインデックスを持ち、 -for文で探索していって非ゼロの要素を見つけたらzeroIndexの要素とスワップして、 -zeroIndexをインクリメントすることで、zeroIndexの左側に非ゼロの要素を集め、 -右側にゼロを集めるという感じ。 - -境界というのを明確にしたいのであればstartZeroIndexとかでもいいかも。またはzeroIndexだとインデックスの値自体が0なのかという誤解を引き起こす恐れがあるので、indexOfStartZeroIndexとかでもいいかもしれない。ただ全体の行数に対して変数名が冗長すぎる気がしたので今回はzeroIndexにした。 -*/ -func moveZeroes(nums []int) { - zeroIndex := 0 - for i, n := range nums { - if n == 0 { - continue - } - nums[zeroIndex], nums[i] = nums[i], nums[zeroIndex] - zeroIndex++ - } -} diff --git a/pullrequests/next_permutation/step1.go b/pullrequests/next_permutation/step1.go deleted file mode 100644 index 1b86702..0000000 --- a/pullrequests/next_permutation/step1.go +++ /dev/null @@ -1,32 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package nextpermutation - -import "sort" - -/* -時間:36分 -解法を思いつくのに時間がかかってしまいました(15分ぐらい)。 -後ろから見ていって昇順になっていない箇所を見つけたら、nums[i-1]よりも大きい中で最小の値を見つけてスワップし、後ろの要素をソートするというやり方を取りました。 -*/ -func nextPermutation_step1(nums []int) { - for i := len(nums) - 1; i > 0; i-- { - if nums[i-1] < nums[i] { - minN := nums[i] - idx := i - for j := i; j < len(nums); j++ { - if nums[j] < minN && nums[i-1] < nums[j] { - idx = j - minN = nums[j] - } - } - nums[i-1], nums[idx] = nums[idx], nums[i-1] - sort.Slice(nums[i:], func(a, b int) bool { - return nums[i+a] < nums[i+b] - }) - return - } - } - sort.Slice(nums, func(a, b int) bool { - return nums[a] < nums[b] - }) -} diff --git a/pullrequests/next_permutation/step2.go b/pullrequests/next_permutation/step2.go deleted file mode 100644 index 60ffc4d..0000000 --- a/pullrequests/next_permutation/step2.go +++ /dev/null @@ -1,28 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package nextpermutation - -import "sort" - -/* -変数名などをリファクタしました。 -*/ -func nextPermutation_step2(nums []int) { - for i := len(nums) - 1; i > 0; i-- { - if nums[i-1] < nums[i] { - candidate, candidateIndex := nums[i], i - for j := i; j < len(nums); j++ { - if nums[j] < candidate && nums[i-1] < nums[j] { - candidate, candidateIndex = nums[j], j - } - } - nums[i-1], nums[candidateIndex] = nums[candidateIndex], nums[i-1] - sort.Slice(nums[i:], func(a, b int) bool { - return nums[i+a] < nums[i+b] - }) - return - } - } - sort.Slice(nums, func(a, b int) bool { - return nums[a] < nums[b] - }) -} diff --git a/pullrequests/next_permutation/step3.go b/pullrequests/next_permutation/step3.go deleted file mode 100644 index e503255..0000000 --- a/pullrequests/next_permutation/step3.go +++ /dev/null @@ -1,30 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package nextpermutation - -/* -これまでの解法がソートを使っていたために時間計算量がO(n log n)になってしまったわけですが、他の人の回答を見てO(n)で解ける方法に変えました。 -nums[i-1]よりも後ろは昇順になっているのを利用し、リバースすればソートできるということに気づきませんでした。 -*/ -func nextPermutation_step3(nums []int) { - if len(nums) < 2 { - return - } - i := len(nums) - 2 - for i >= 0 && nums[i] >= nums[i+1] { - i-- - } - if i >= 0 { - j := len(nums) - 1 - for nums[j] <= nums[i] { - j-- - } - nums[i], nums[j] = nums[j], nums[i] - } - reverse(nums[i+1:]) -} - -func reverse(nums []int) { - for i, j := 0, len(nums)-1; i < j; i, j = i+1, j-1 { - nums[i], nums[j] = nums[j], nums[i] - } -} diff --git a/pullrequests/palindrome_number/step2.go b/pullrequests/palindrome_linked_list/step1.go similarity index 54% rename from pullrequests/palindrome_number/step2.go rename to pullrequests/palindrome_linked_list/step1.go index cedc9d5..2d2e233 100644 --- a/pullrequests/palindrome_number/step2.go +++ b/pullrequests/palindrome_linked_list/step1.go @@ -1,7 +1,10 @@ //lint:file-ignore U1000 Ignore all unused code -package palindromenumber +package palindromelinkedlist -import "strconv" +type ListNode struct { + Val int + Next *ListNode +} /* レビュワーの方へ: @@ -9,17 +12,23 @@ import "strconv" */ /* -一応、文字列に変換する方法でも解いてみた。 +時間:5分 +スライスに変換し、Palindromeかどうかを比較するようにした。 */ -func isPalindromeStep2(x int) bool { - strX := strconv.Itoa(x) - i, j := 0, len(strX)-1 - for i < j { - if strX[i] != strX[j] { +func isPalindromeLinkedList(head *ListNode) bool { + var values []int + node := head + for node != nil { + values = append(values, node.Val) + node = node.Next + } + left, right := 0, len(values)-1 + for left < right { + if values[left] != values[right] { return false } - i++ - j-- + left++ + right-- } return true } diff --git a/pullrequests/palindrome_number/step1.go b/pullrequests/palindrome_number/step1.go deleted file mode 100644 index f35ae4c..0000000 --- a/pullrequests/palindrome_number/step1.go +++ /dev/null @@ -1,22 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package palindromenumber - -/* -レビュワーの方へ: - - このコードは既にGoの標準のフォーマッタで整形済みです。演算子の周りにスペースがあったりなかったりしますが、これはGoのフォーマッタによるもので、優先順位の高い演算子の周りにはスペースが入らず、低い演算子の周りには入るようになっています。https://qiita.com/tchssk/items/77030b4271cd192d0347 -*/ - -/* -時間:8分50秒 -最初に思いついたのは文字列に変換してチェックする方法だが、LeetCode上に文字列に変換しないで求めてみよと書かれていたのでまずは下記のようにして解いた。 -*/ -func isPalindromeStep1(x int) bool { - var reversed int - tmp := x - for tmp > 0 { - n := tmp % 10 - reversed = reversed*10 + n - tmp /= 10 - } - return x == reversed -} diff --git a/pullrequests/search_in_rotated_sorted_array/step1.go b/pullrequests/search_in_rotated_sorted_array/step1.go deleted file mode 100644 index f54e0f3..0000000 --- a/pullrequests/search_in_rotated_sorted_array/step1.go +++ /dev/null @@ -1,31 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package template - -/* -O(log n)で解くことを期待されていたので、何らかの形で二分探索を使うのだろうとは思っていたのですが、初見では解けなかったので、他の人の回答を参考にしました。 -どちらか片方は必ず必ず昇順にならんでいるということを利用して二分探索を行っています。 -下記は閉区画で解きました。 -*/ -func search_closed(nums []int, target int) int { - left, right := 0, len(nums)-1 - for left <= right { - mid := (left + right) / 2 - if target == nums[mid] { - return mid - } - if nums[left] <= nums[mid] { - if nums[left] <= target && target < nums[mid] { - right = mid - 1 - } else { - left = mid + 1 - } - } else { - if nums[mid] < target && target <= nums[right] { - left = mid + 1 - } else { - right = mid - 1 - } - } - } - return -1 -} diff --git a/pullrequests/search_in_rotated_sorted_array/step2.go b/pullrequests/search_in_rotated_sorted_array/step2.go deleted file mode 100644 index 59d3105..0000000 --- a/pullrequests/search_in_rotated_sorted_array/step2.go +++ /dev/null @@ -1,29 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package template - -/* -半閉区画でも解いてみました。 -*/ -func search_half_closed(nums []int, target int) int { - left, right := 0, len(nums) - for left < right { - mid := (left + right) / 2 - if target == nums[mid] { - return mid - } - if nums[left] <= nums[mid] { - if nums[left] <= target && target < nums[mid] { - right = mid - } else { - left = mid + 1 - } - } else { - if nums[mid] < target && target <= nums[right-1] { - left = mid + 1 - } else { - right = mid - } - } - } - return -1 -} diff --git a/pullrequests/single_number/step1.go b/pullrequests/single_number/step1.go deleted file mode 100644 index b61f0be..0000000 --- a/pullrequests/single_number/step1.go +++ /dev/null @@ -1,26 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package singlenumber - -/* -レビュワーの方へ: - - このコードは既にGoの標準のフォーマッタで整形済みです。演算子の周りにスペースがあったりなかったりしますが、これはGoのフォーマッタによるもので、優先順位の高い演算子の周りにはスペースが入らず、低い演算子の周りには入るようになっています。https://qiita.com/tchssk/items/77030b4271cd192d0347 -*/ - -/* -時間:3分 -LeetCodeには空間計算量がO(1)になるように実装しろと書かれていたが、方法が思いつかなかったので、まずは普通に実装してみた。 -*/ -func singleNumberStep1(nums []int) int { - singleNums := make(map[int]int, len(nums)) - for _, n := range nums { - singleNums[n]++ - if singleNums[n] > 1 { - delete(singleNums, n) - } - } - // 必要に応じてlen(singleNums) != 1のときはエラーを返すという処理も追加しても良いかも - for n := range singleNums { - return n - } - return 0 // 本来は見つからなかった場合はエラーを返したい -} diff --git a/pullrequests/single_number/step2.go b/pullrequests/single_number/step2.go deleted file mode 100644 index 35834a2..0000000 --- a/pullrequests/single_number/step2.go +++ /dev/null @@ -1,19 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package singlenumber - -/* -レビュワーの方へ: - - このコードは既にGoの標準のフォーマッタで整形済みです。演算子の周りにスペースがあったりなかったりしますが、これはGoのフォーマッタによるもので、優先順位の高い演算子の周りにはスペースが入らず、低い演算子の周りには入るようになっています。https://qiita.com/tchssk/items/77030b4271cd192d0347 -*/ - -/* -調べたところ下記のようにすれば空間計算量がO(1)になる。 -ただし、このXORを使った方法は1つの数以外は全て偶数回必ず出現するという条件を満たさなければ成立しないので、実際にこのように書くのが良い方法だとは思わなかった(ただしビット演算の練習にはなる)。 -*/ -func singleNumberStep2(nums []int) int { - singleNum := 0 - for _, n := range nums { - singleNum ^= n - } - return singleNum -} diff --git a/pullrequests/symmetric_tree/step1.go b/pullrequests/symmetric_tree/step1.go deleted file mode 100644 index ad88730..0000000 --- a/pullrequests/symmetric_tree/step1.go +++ /dev/null @@ -1,35 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package symmetrictree - -type TreeNode struct { - Val int - Left *TreeNode - Right *TreeNode -} - -/* -レビュワーの方へ: - - このコードは既にGoの標準のフォーマッタで整形済みです。演算子の周りにスペースがあったりなかったりしますが、これはGoのフォーマッタによるもので、優先順位の高い演算子の周りにはスペースが入らず、低い演算子の周りには入るようになっています。https://qiita.com/tchssk/items/77030b4271cd192d0347 -*/ - -/* -初見で解くことができなかったので、他の解法を見て解いた。再帰の練習が足りてなさそう。 -*/ -func isSymmetricRecursive(root *TreeNode) bool { - // 問題的にはrootはnilにならないのでこの処理は必要ないが - // 一応nilのときはtrue扱いにすると決めて書いた - if root == nil { - return true - } - return isMirror(root.Left, root.Right) -} - -func isMirror(left, right *TreeNode) bool { - if left == nil && right == nil { - return true - } - if left == nil || right == nil { - return false - } - return left.Val == right.Val && isMirror(left.Left, right.Right) && isMirror(left.Right, right.Left) -} diff --git a/pullrequests/symmetric_tree/step2.go b/pullrequests/symmetric_tree/step2.go deleted file mode 100644 index 37ab6b1..0000000 --- a/pullrequests/symmetric_tree/step2.go +++ /dev/null @@ -1,36 +0,0 @@ -//lint:file-ignore U1000 Ignore all unused code -package symmetrictree - -import "container/list" - -/* -レビュワーの方へ: - - このコードは既にGoの標準のフォーマッタで整形済みです。演算子の周りにスペースがあったりなかったりしますが、これはGoのフォーマッタによるもので、優先順位の高い演算子の周りにはスペースが入らず、低い演算子の周りには入るようになっています。https://qiita.com/tchssk/items/77030b4271cd192d0347 -*/ - -/* -イテレーティブにも解いてみた。BFSなのでキューを使って実装した。 -*/ -func isSymmetric(root *TreeNode) bool { - if root == nil { - return true - } - queue := list.New() - queue.PushBack(root.Left) - queue.PushBack(root.Right) - for queue.Len() > 0 { - left := queue.Remove(queue.Front()).(*TreeNode) - right := queue.Remove(queue.Front()).(*TreeNode) - if left == nil && right == nil { - continue - } - if left == nil || right == nil || left.Val != right.Val { - return false - } - queue.PushBack(left.Left) - queue.PushBack(right.Right) - queue.PushBack(left.Right) - queue.PushBack(right.Left) - } - return true -}