package daily
import "slices"
// 20231124
// Problem 1561: Maximum Number of Coins You Can Get
// https://leetcode.com/problems/maximum-number-of-coins-you-can-get
// Difficulty: Medium
// maxCoins returns the maximum number of coins you can get by following the rules below:
// - There are 3n piles of coins of varying size.
// - In each step, you will choose any 3 piles of coins (not necessarily consecutive).
// - Take the second largest pile of coins and add it to your collection.
// - Return the maximum number of coins you can get.
func maxCoins(piles []int) int {
var ans int
// Sort the piles in ascending order.
slices.Sort(piles)
// Drop the first n/3 piles, as we'll never choose them.
piles = piles[len(piles)/3:]
// Sum every other pile, as we'll always choose the largest pile.
for i := 0; i < len(piles); i += 2 {
ans += piles[i]
}
return ans
}
package daily
import "slices"
// 20231123
// Problem 1630: Arithmetic Subarrays
// https://leetcode.com/problems/arithmetic-subarrays
// Difficulty: Medium
// This solution is not the most efficient, as there's a number theory solution that doesn't
// require sorting. However, this solution is simple and easy to understand, and still passes
// all the test cases in LeetCode.
// checkArithmeticSubarrays returns a slice of booleans indicating whether each subarray
// defined by the given l and r slices is an arithmetic sequence.
func checkArithmeticSubarrays(nums []int, l []int, r []int) []bool {
var results []bool
for i := 0; i < len(l); i++ {
// We need to make a copy of the subarray because we're going to sort it.
subarray := make([]int, r[i]-l[i]+1)
copy(subarray, nums[l[i]:r[i]+1])
results = append(results, isArithmetic(subarray))
}
return results
}
// isArithmetic returns true if the given slice of integers is an arithmetic sequence, and
// false otherwise.
func isArithmetic(nums []int) bool {
// Base cases that don't require sorting.
if len(nums) < 2 {
return false
} else if len(nums) == 2 {
return true
}
// Sort the slice and check if the difference between each pair of numbers is the same.
slices.Sort(nums)
diff := nums[1] - nums[0]
for i := 2; i < len(nums); i++ {
if nums[i]-nums[i-1] != diff {
return false
}
}
return true
}
package daily
// 20231125
// Problem 1685: Sum of Absolute Differences in a Sorted Array
// https://leetcode.com/problems/sum-of-absolute-differences-in-a-sorted-array
// Difficulty: Medium
// Turns out calculating the suffix sum wasn't necessary, and likely cost some memory.
// Per a comment on the problem, just the prefix is needed:
// result[i] = (nums[i]*i - pre[i]) + (pre[n]-pre[i] - nums[i]*(n-i))
// getSumAbsoluteDifferences returns an array ans of length n, where ans[i] is the sum of
// absolute differences between nums[i] and all the other elements in the array.
func getSumAbsoluteDifferences(nums []int) []int {
var (
ans, prefix, suffix = make([]int, len(nums)), make([]int, len(nums)), make([]int, len(nums))
n = len(nums)
)
// Calculate the prefix and suffix sums.
prefix[0] = nums[0]
suffix[n-1] = nums[n-1]
for i := 1; i < len(nums); i++ {
prefix[i] = prefix[i-1] + nums[i]
suffix[n-i-1] = suffix[n-i] + nums[n-i-1]
}
// We can calculate the answer for each index i by using the prefix and suffix sums.
for i := 0; i < len(nums); i++ {
left := i*nums[i] - prefix[i]
right := suffix[i] - nums[i]*(n-i-1)
ans[i] = left + right
}
return ans
}
package daily
// 20231128
// Problem 2147: Number of Ways to Divide a Long Corridor
// https://leetcode.com/problems/number-of-ways-to-divide-a-long-corridor
// Difficulty: Hard
// numberOfWays returns the number of ways to divide the corridor.
func numberOfWays(corridor string) int {
var (
ans, seenSeats, seenPlants int
)
// Iterate over each character in the corridor.
for _, c := range corridor {
if c == 'S' {
seenSeats++
if seenSeats == 2 && ans < 1 {
// We only start caring about the number of plants when we've seen two seats.
ans = 1
} else if seenSeats == 3 {
// We've seen a third seat, so we sum the answer with seenPlants+1, with the modulo to prevent an overflow.
ans = ans * (seenPlants + 1) % (1e9 + 7)
// Reset the seen seats and plants.
seenSeats = 1
seenPlants = 0
}
} else if seenSeats == 2 {
// We only care about the number of plants when we've seen two seats.
seenPlants++
}
}
// If there are an odd number of seats, then there are no ways to divide the corridor.
if seenSeats == 1 {
return 0
}
return ans
}
package l75
import (
"strings"
)
// 20231125
// LeetCode 75
// Problem 1071: Greatest Common Divisor of Strings
// https://leetcode.com/problems/greatest-common-divisor-of-strings
// Difficulty: Easy
// This solution can be simplified further. If str1 + str2 != str2 + str1, then return "".
// If they are equal, str[:gcd] is the greatest common divisor of str1 and str2.
// gcdOfStrings returns the greatest common divisor of strings str1 and str2.
func gcdOfStrings(str1 string, str2 string) string {
// If str1 == str2, return str1.
if str1 == str2 {
return str1
}
// If either string is empty, return "".
if len(str1) == 0 || len(str2) == 0 {
return ""
}
// Find the greatest common divisor of the lengths of str1 and str2.
gcd := getGCD(len(str1), len(str2))
gcdStr := str1[:gcd]
// If str1[:gcd] is a divisor of str1 and str2, return str1[:gcd].
if str1 == strings.Repeat(gcdStr, len(str1)/gcd) && str2 == strings.Repeat(gcdStr, len(str2)/gcd) {
return gcdStr
}
return ""
}
// getGCD returns the greatest common divisor of two integers.
func getGCD(a, b int) int {
// Euclidean algorithm
if a == 0 {
return b
}
return getGCD(b%a, a)
}
package l75
// 20231124
// LeetCode 75
// Problem 1768: Merge Strings Alternately
// https://leetcode.com/problems/merge-strings-alternately
// Difficulty: Easy
// Optimal solution evidently uses a string builder.
// mergeAlternately returns the merge of word1 and word2, where the merge is formed by
// alternating the letters in word1 and word2, starting with word1. If one of the words
// is longer than the other, then the remaining letters in the longer word should be
// appended at the end of the merge.
func mergeAlternately(word1 string, word2 string) string {
var ans []byte
// Iterate over the shorter word, then append the remaining letters of the longer word.
short := min(len(word1), len(word2))
for i := 0; i < short; i++ {
ans = append(ans, word1[i], word2[i])
}
// Append the remaining letters of the longer word.
if len(word1) > len(word2) {
ans = append(ans, word1[short:]...)
} else if len(word2) > len(word1) {
ans = append(ans, word2[short:]...)
}
return string(ans)
}