LeetCode Questions - Medium
- LeetCode Questions - Medium
- Environment Setup
- All Permutations and Combinations(PowerSet)
- 534. Design TinyURL
- 8. String to Integer (atoi)
- 151. Reverse Words in a String
- 29. Divide Two Integers
- 166. Fraction to Recurring Decimal
- 220. Contains Duplicate III
- 127. Word Ladder
- 91. Decode Ways
- 165. Compare Version Numbers
- 457. Circular Array Loop
- 468. Validate IP Address
- 184. Department Highest Salary
- 177. Nth Highest Salary
- 15. 3Sum
- 307. Range Sum Query - Mutable
- 54. Spiral Matrix
- 40. Combination Sum II
- 114. Flatten Binary Tree to Linked List
LeetCode Questions - Medium
Environment Setup
TypeScript Playground: https://www.typescriptlang.org/play/
Scala Playground: https://scastie.scala-lang.org/
Scala/Js/CodeSnippet Playground2: https://leetcode.com/playground/new
Covert Tabs to Spaces in Code Snippets: http://tabstospaces.com/
All Permutations and Combinations(PowerSet)
object Permutations {
def permutations(s: String): List[String] = {
def merge(ins: String, c: Char): Seq[String] =
for (i <- 0 to ins.length) yield
ins.substring(0, i) + c + ins.substring(i, ins.length)
if (s.length() == 1)
List(s)
else
permutations(s.substring(0, s.length - 1)).flatMap { p =>
merge(p, s.charAt(s.length - 1))
}
}
}
534. Design TinyURL
Source: https://leetcode.com/problems/design-tinyurl/description/
How would you design a URL shortening service that is similar to TinyURL?
Background:
TinyURL is a URL shortening service where you enter a URL such as https://leetcode.com/problems/design-tinyurl
and it returns a short URL such as http://tinyurl.com/4e9iAk
.
Requirements:
For instance, "http://tinyurl.com/4e9iAk"
is the tiny url for the page "https://leetcode.com/problems/design-tinyurl"
. The identifier can be any string with 6 alphanumeric characters containing 0-9
, a-z
, A-Z
.
Each shortened URL must be unique; that is, no two different URLs can be shortened to the same URL.
TypeScript Solution:
const DICTIONARY: string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
const URL_PREFIX: string = "http://tiny.url/";
const CODE_0: number = "0".charCodeAt(0);
const CODE_9: number = "9".charCodeAt(0);
const CODE_LOWER_A: number = "a".charCodeAt(0);
const CODE_LOWER_Z: number = "z".charCodeAt(0);
const CODE_UPPER_A: number = "A".charCodeAt(0);
const CODE_UPPER_Z: number = "Z".charCodeAt(0);
class URLService {
private _stol: Map<number, string>;
private _counter: number;
constructor() {
this._stol = new Map<number, string>();
this._counter = 1;
}
public longToShort(url: string): string {
let shorturl = URLService.base10ToBase62(this._counter);
this._stol.set(this._counter, url);
this._counter++;
return URL_PREFIX + shorturl;
}
public shortToLong(url: string): string {
let urlParam: string = url.substring(URL_PREFIX.length);
let n: number = URLService.base62ToBase10(urlParam);
return this._stol.get(n);
}
public static convert(charCode: number): number {
if (charCode >= CODE_0 && charCode <= CODE_9) {
return charCode - CODE_0;
} else if (charCode >= CODE_LOWER_A && charCode <= CODE_LOWER_Z) {
return charCode - CODE_LOWER_A + 10;
} else if (charCode >= CODE_UPPER_A && charCode <= CODE_UPPER_Z) {
return charCode - CODE_UPPER_A + 36;
} else {
return -1;
}
}
public static base62ToBase10(s: string): number {
let n: number = 0;
for (let i: number = 0; i < s.length; i++) {
n = n * 62 + URLService.convert(s.charCodeAt(i));
}
return n;
}
public static base10ToBase62(n: number): string {
let s: string = "";
while (n !== 0) {
let r: number = n % 62;
n = (n - r) / 62;
s = DICTIONARY[r] + s;
}
while (s.length < 6) {
s = "0" + s;
}
return s;
}
}
function exec() {
const service: URLService = new URLService();
let result: string = service.shortToLong(service.longToShort("http://trsong.github.io/"));
let div: HTMLElement = document.createElement("div");
div.innerText = result;
document.body.appendChild(div);
}
exec();
Scala Soluction:
import scala.collection.mutable.{StringBuilder, HashMap}
class URLService {
private var counter: BigInt = BigInt(1)
private val stol = HashMap.empty[BigInt, String]
def longToShort(url: String): String = {
val shorturl = URLService.base10ToBase62(counter)
stol(counter) = url
counter += 1
URLService.urlPrefix + shorturl
}
def shortToLong(url: String): String = {
val urlParam = url.substring(URLService.urlPrefix.length)
stol.getOrElse(URLService.base62ToBase10(urlParam), URLService.urlPrefix)
}
}
object URLService {
val dictionary = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
val urlPrefix = "http://tiny.url/"
def convert(c: Char): Int = c match {
case num if num >= '0' && num <= '9' => num - '0'
case lower if lower >= 'a' && lower <= 'z' => lower - 'a' + 10
case upper if upper >= 'A' && upper <= 'Z' => upper - 'A' + 36
case _ => -1
}
def base62ToBase10(s: String): BigInt = {
(BigInt(0) /: s)(62 * _ + convert(_) )
}
def base10ToBase62(n: BigInt): String = {
val sb = new StringBuilder
var target = n
while (target != 0) {
sb += dictionary((target % 62).toInt)
target = target / 62
}
while (sb.size < 6) {
sb += '0'
}
sb.toString().reverse
}
}
object Main extends App {
val service = new URLService
println(service.shortToLong(service.longToShort("http://trsong.github.io/")))
}
8. String to Integer (atoi)
Source: https://leetcode.com/problems/string-to-integer-atoi/description/
Implement atoi to convert a string to an integer.
Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases.
Requirements for atoi:
The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.
The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.
If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.
If no valid conversion could be performed, a zero value is returned. If the correct value is out of the range of representable values, INT_MAX (2147483647) or INT_MIN (-2147483648) is returned.
TypeScript Solution:
const INT_MAX: number = 2147483647;
const INT_MIN: number = -2147483648;
function atoi(str: string): number {
let index: number = 0, sign: number = 1, total: number = 0;
// 1. Empty string
if (!str || str.length === 0) return 0;
// 2. Remove whitespace
while(index < str.length && str[index] === ' ') index++;
// 3. Handle signs
while (index < str.length && (str[index] === '+' || str[index] === '-')) {
sign = str[index] === '+' ? sign : -sign;
index++;
}
// 4. Convert number and avoid overflow
while (index < str.length) {
let digit: number = str.charCodeAt(index) - "0".charCodeAt(0);
if (digit < 0 || digit > 9) {
total = 0;
break;
}
total = 10 * total + digit;
index++;
if (total > INT_MAX && sign > 0) return INT_MAX;
else if (total > -INT_MIN && sign < 0) return INT_MIN;
}
return total * sign;
}
function exec() {
let result: number = atoi(" -+-++-42");
let div: HTMLElement = document.createElement("div");
div.innerText = result.toString();
document.body.appendChild(div);
}
exec();
Scala Soluction:
object Main extends App {
val INT_MAX: Int = 2147483647
val INT_MIN: Int = -2147483648
def atoi(str: String): Int = {
var index = 0
var sign = 1
var total = 0
var isValid = true
// 1. Empty string
// 2. Remove whitespaces
while (index < str.length && str(index) == ' ') {
index += 1
}
// 3. Handle sign
while (index < str.length && (str(index) == '+' || str(index) == '-')) {
sign = if (str(index) == '+') sign else -sign
index += 1
}
// 4. Convert number and avoid overflow
while (index < str.length) {
val digit = str(index) - '0'
if (!isValid || digit < 0 || digit > 9) {
isValid = false
} else if (sign > 0 && digit > (INT_MAX - digit) / 10) {
total = INT_MAX
} else if (sign < 0 && digit > (- digit - INT_MIN) / 10) {
total = INT_MIN
} else {
total = 10 * total + digit
}
index += 1
}
if (isValid) total * sign else 0
}
println(atoi("2147483647"))
println(atoi("-2147483648"))
println(atoi("42"))
println(atoi(" -++----42"))
println(atoi(""))
println(atoi(" + - - + "))
}
151. Reverse Words in a String
Source: https://leetcode.com/problems/reverse-words-in-a-string/description/
Given an input string, reverse the string word by word.
For example,
Given s = “the sky is blue
”,
return “blue is sky the
”.
Try to solve it in-place in O(1) space.
Clarification:
-
Q: What constitutes a word? A: A sequence of non-space characters constitutes a word.
-
Q: Could the input string contain leading or trailing spaces? A: Yes. However, your reversed string should not contain leading or trailing spaces.
-
Q: How about multiple spaces between two words? A: Reduce them to a single space in the reversed string.
TypeScript Solution:
const CODE_WHITE_SPACE: number = " ".charCodeAt(0);
class Solution {
public static reverseWords(s: string): string {
if (!s) return undefined;
let a: number[] = Array.from({length: s.length}, (_, index: number) => s.charCodeAt(index));
// 1. Reverse the whole string
Solution.reverse(a, 0, a.length - 1);
// 2. Reverse each word in place
Solution.reverseEachWordInPlace(a);
// 3. Clean up spaces and return
return Solution.cleanSpaces(a);
}
// reverse a[] from a[i] to a[j]
private static reverse(a: number[], i: number, j: number): void {
while (i < j) {
[a[i++], a[j--]] = [a[j], a[i]]
}
}
// scan through and reverse each word in place
private static reverseEachWordInPlace(a: number[]): void {
let i: number = 0, j: number = 0;
while (i < a.length) {
while (i < j || i < a.length && a[i] === CODE_WHITE_SPACE) i++; // Skip spaces
while (j < i || j < a.length && a[j] !== CODE_WHITE_SPACE) j++; // Skip non spaces
Solution.reverse(a, i, j - 1); // reverse the word
}
}
// trim leading, trailling and multiple spaces
private static cleanSpaces(a: number[]): string {
let i: number = 0, j: number = 0;
while (j < a.length) {
while (j < a.length && a[j] === CODE_WHITE_SPACE) j++; // skip spaces
while (j < a.length && a[j] !== CODE_WHITE_SPACE) a[i++] = a[j++]; // keep non spaces
while (j < a.length && a[j] === CODE_WHITE_SPACE) j++; // skip spaces
if (j < a.length) a[i++] = CODE_WHITE_SPACE; // keep only one space between consecutive word
}
return a.slice(0, i).map((code: number) => String.fromCharCode(code)).join('');
}
}
function exec() {
let result: string = Solution.reverseWords(" Hello World !");
let div: HTMLElement = document.createElement("div");
div.innerText = result;
document.body.appendChild(div);
}
exec();
Scala Soluction:
import scala.collection.mutable.Buffer
object Solution {
def reverseWords(s: String): String = {
val sb = s.toBuffer
// 1. reverse the input string
reverse(sb, 0, sb.size - 1)
// 2. reverse each word in place
reverseEachWordInPlace(sb)
// 3. clean spaces and return
cleanSpaces(sb)
}
// Reverse the sb from sb(start) to sb(end)
private def reverse(sb: Buffer[Char], start: Int, end: Int): Unit = {
var (i, j) = (start, end)
while (i < j) {
val tmp = sb(i)
sb(i) = sb(j)
sb(j) = tmp
i += 1
j -= 1
}
}
// Scan through each word and reverse them in place
private def reverseEachWordInPlace(sb: Buffer[Char]): Unit = {
var (i, j) = (0, 0)
while (i < sb.size) {
while (i < j || i < sb.size && sb(i) == ' ') i += 1
while (j < i || j < sb.size && sb(j) != ' ') j += 1
reverse(sb, i, j - 1)
}
}
// Remove the leading, tailing and multiple white spaces
private def cleanSpaces(sb: Buffer[Char]): String = {
var (i, j) = (0, 0)
while (j < sb.size) {
while (j < sb.size && sb(j) == ' ') j += 1
while (j < sb.size && sb(j) != ' ') {
sb(i) = sb(j)
i += 1
j += 1
}
while (j < sb.size && sb(j) == ' ') j += 1
if (j < sb.size) {
sb(i) = ' '
i += 1
}
}
sb.take(i).mkString
}
}
object Main extends App {
println(Solution.reverseWords(" Hello World !"))
}
29. Divide Two Integers
Source: https://leetcode.com/problems/divide-two-integers/description/
Divide two integers without using multiplication, division and mod operator.
If it is overflow, return MAX_INT.
Hint:
n = n0 + d * 2 ^ m0 where d <= n0 < 2d, n > d
n0 = n1 + d * 2 ^ m1 where d <= n1 < 2d, n0 > d
...
n_{k-1} = nk + d * 2 ^ 0 where 0 <= nk < d,
ans = 2^m0 + 2^m1 + ... + 1
eg.
divide(16, 3)
16 = 4 + 3 * 2^2
4 = 1 + 3 * 2^0
ans = 2^2 + 2^0 = 5
Note:
n = d * ans = d * (1 << m0 + 1 << m1 + ... + 1 << 0)
worese case: n = 2^p - 1, d = 1
Time Complexity: O((Log N) ^ 2)
N in binary has Log(N) digits
So we need to have Log(N) step with each step spend Log(N) to figure out m
TypeScript Solution:
function divide(n: number, d: number): number {
// Edge case optimization
if (d == 1) return n;
// Error/Overflow handling
if (d == 0 || (n == Number.MIN_SAFE_INTEGER && d == -1)) return Number.MAX_SAFE_INTEGER;
let result: number = 0;
let n0: number = Math.abs(n);
let d0: number = Math.abs(d);
while (n0 >= d0) {
let a: number = d0;
let m: number = 1;
while ((a << 1) < n0) {
a <<= 1;
m <<= 1;
}
result += m;
n0 -= a;
}
if ((n > 0) !== (d > 0)) { // XOR
result = -result;
}
return result;
}
function exec() {
let result: number = divide(16, 3);
let div: HTMLElement = document.createElement("div");
div.innerText = result.toString();
document.body.appendChild(div);
}
exec();
Scala Soluction:
object Main extends App {
def divide(n: Int, d: Int): Int = {
if (d == 1) n // edge case optimization
else if (d == 0 || (n == Int.MinValue && d == -1)) Int.MaxValue // Handling overflow
else {
var result = 0
var n0 = Math.abs(n)
var d0 = Math.abs(d)
while (n0 > d0) {
var a = d0
var m = 1
while ((a << 1) < n0) {
a <<= 1
m <<= 1
}
result += m
n0 -= a
}
if ((n > 0) ^ (d > 0)) result = -result
result
}
}
println(divide(72, 1))
println(divide(16, 3))
println(divide(Int.MinValue, -1))
println(divide(Int.MaxValue, 1))
}
166. Fraction to Recurring Decimal
Source: https://leetcode.com/problems/fraction-to-recurring-decimal/description/
Given two integers representing the numerator and denominator of a fraction, return the fraction in string format.
If the fractional part is repeating, enclose the repeating part in parentheses.
For example,
- Given numerator = 1, denominator = 2, return “0.5”.
- Given numerator = 2, denominator = 1, return “2”.
- Given numerator = 2, denominator = 3, return “0.(6)”.
- Given numerator = 61, denominator = 30, return “2.0(3)”.
TypeScript Solution:
function fractionToDecimal(numerator: number, denominator: number): string {
let result: string = "";
let sign: string = (numerator < 0) !== (denominator < 0) ? "-" : "";
let n: number = Math.abs(numerator);
let d: number = Math.abs(denominator);
result += sign;
let remainder: number = n % d;
if (remainder === 0) {
result += n / d;
return result;
}
result += (n - remainder) / d;
result += ".";
let remainderPosMap: Map<number, number> = new Map<number, number>();
while (!remainderPosMap.has(remainder)) {
remainderPosMap.set(remainder, result.length);
let nextRemainder: number = remainder * 10 % d;
result += (remainder * 10 - nextRemainder) / d;
remainder = nextRemainder;
}
let index: number = remainderPosMap.get(remainder);
let prifixTerm: string = result.slice(0, index);
let repeatedTerm: string = result.slice(index);
if (repeatedTerm !== "0") {
result = `${prifixTerm}(${repeatedTerm})`;
} else {
result = prifixTerm;
}
return result;
}
function exec() {
let result: string = fractionToDecimal(61, 30);
let div: HTMLElement = document.createElement("div");
div.innerText = result;
document.body.appendChild(div);
}
exec();
Scala Soluction:
import scala.collection.mutable.{HashMap, StringBuilder}
object Main extends App {
def fractionToDecimal(numerator: Int, denominator: Int): String = {
val sb = StringBuilder.newBuilder
if ((numerator < 0) ^ (denominator < 0)) sb += '-'
val n = Math.abs(numerator)
val d = Math.abs(denominator)
sb.append(n / d)
var remainder = n % d
if (remainder == 0) sb.result
else {
sb += '.'
val remainderPosMap = HashMap.empty[Int, Int]
while (!remainderPosMap.contains(remainder)) {
remainderPosMap(remainder) = sb.size
sb.append(10 * remainder / d)
remainder = 10 * remainder % d
}
val index = remainderPosMap(remainder)
val repeatedTerm = sb.slice(index, sb.size)
if (repeatedTerm.size == 1 && repeatedTerm(0) == '0') {
sb.dropRight(1).result // strip the tailing 0
} else {
sb.insert(index, '(')
sb += ')'
sb.result
}
}
}
println(fractionToDecimal(61, 30))
println(fractionToDecimal(61, -30))
println(fractionToDecimal(60, 30))
println(fractionToDecimal(61, 10))
}
220. Contains Duplicate III
Source: https://leetcode.com/problems/contains-duplicate-iii/description/
Given an array of integers, find out whether there are two distinct indices i and j in the array such that the absolute difference between nums[i] and nums[j] is at most t and the absolute difference between i and j is at most k.
Eg. Exists different indices i, j such that abs(nums[i] - num[j]) <= t and abs(i - j) <= k
Hint:
The idea is like the bucket sort algorithm. Suppose we have consecutive buckets covering the range of nums with each bucket a width of (t+1). If there are two item with difference <= t, one of the two will happen:
(1) the two in the same bucket
(2) the two in neighbor buckets
- For case (1) return true directly, since they are within the same bucket of t + 1
- For case (2) check if abs(nums[i] - num[j]) <= t
- For other case, we move on
Note, while we iterator through the list, we keep a index window of k, means any nums[j] with j < i - k
will no longer take into consideration.
TypeScript Solution:
function getBucketIndex(value: number, windowSize: number): number {
return Math.floor(value < 0 ? value / windowSize - 1 : value / windowSize);
}
// Check if exists different indices i, j such that abs(nums[i] - num[j]) <= t and abs(i - j) <= k
function containsNearbyAlmostDuplicate(nums: number[], k: number, t: number): boolean {
if (k < 1 || t < 0) return false;
let bucket: Map<number, number> = new Map<number, number>();
let w: number = t + 1;
for (let i: number = 0; i < nums.length; i++) {
let bucketIndex: number = getBucketIndex(nums[i], w);
if (bucket.has(bucketIndex) ||
(bucket.has(bucketIndex - 1) && Math.abs(bucket.get(bucketIndex - 1) - nums[i]) < w) ||
(bucket.has(bucketIndex + 1) && Math.abs(bucket.get(bucketIndex + 1) - nums[i]) < w)) {
return true;
}
bucket.set(bucketIndex, nums[i]);
if (i >= k) bucket.delete(getBucketIndex(nums[i - k], w));
}
return false;
}
function exec() {
let result: boolean = containsNearbyAlmostDuplicate([-1, -5, 7, 3, 9, -3], 2, 2);
let result2: boolean = containsNearbyAlmostDuplicate([-1, -5, 7, 3, 9, -3], 1, 2);
let div: HTMLElement = document.createElement("div");
div.innerText = result.toString();
div.innerText += " \n " + result2.toString();
document.body.appendChild(div);
}
exec();
Scala Soluction:
object Main extends App {
// Check if exists different indices i, j such that abs(nums[i] - num[j]) <= t and abs(i - j) <= k
def containsNearbyAlmostDuplicate(nums: IndexedSeq[Int], k: Int, t: Int): Boolean = {
val windowSize = t + 1
def getBucketIndex(value: Int) = if (value < 0) value / windowSize - 1 else value / windowSize
if (k < 1 || t < 0) false
else nums.zipWithIndex.foldLeft((false, Map.empty[Int, Int])) { (memo, valueAndIndex) =>
val (result, bucket) = memo
val (value, i) = valueAndIndex
val bucketIndex = getBucketIndex(value)
if (result || bucket.contains(bucketIndex) ||
(bucket.contains(bucketIndex - 1) && Math.abs(bucket(bucketIndex - 1) - value) < windowSize) ||
(bucket.contains(bucketIndex + 1) && Math.abs(bucket(bucketIndex + 1) - value) < windowSize)) {
(true, bucket)
} else {
val updatedBucket = bucket + (bucketIndex -> value)
(false, if (i >= k) updatedBucket - getBucketIndex(nums(i - k)) else updatedBucket)
}
}._1
}
println(containsNearbyAlmostDuplicate(Array(-1, -5, 7, 3, 9, -3), 2, 2))
println(containsNearbyAlmostDuplicate(Array(-1, -5, 7, 3, 9, -3), 1, 2))
}
127. Word Ladder
Source: https://leetcode.com/problems/word-ladder/description/
Given two words (beginWord and endWord), and a dictionary’s word list, find the length of shortest transformation sequence from beginWord to endWord, such that:
- Only one letter can be changed at a time.
- Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
For example,
Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log","cog"]
As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.
Note:
- Return 0 if there is no such transformation sequence.
- All words have the same length.
- All words contain only lowercase alphabetic characters.
- You may assume no duplicates in the word list.
- You may assume beginWord and endWord are non-empty and are not the same.
Hint:
Well, this problem has a nice BFS structure.
Let’s see the example in the problem statement.
start = "hit"
end = "cog"
dict = ["hot", "dot", "dog", "lot", "log"]
Since only one letter can be changed at a time, if we start from "hit"
, we can only change to those words which have only one different letter from it, like "hot"
. Putting in graph-theoretic terms, we can say that "hot"
is a neighbor of "hit"
.
The idea is simpy to begin from start
, then visit its neighbors, then the non-visited neighbors of its neighbors… Well, this is just the typical BFS structure.
To simplify the problem, we insert end
into dict
. Once we meet end
during the BFS, we know we have found the answer. We maintain a variable dist
for the current distance of the transformation and update it by dist++
after we finish a round of BFS search (note that it should fit the definition of the distance in the problem statement). Also, to avoid visiting a word for more than once, we erase it from dict
once it is visited.
TypeScript Solution: (One-way BFS)
const CODE_LOWER_A: number = "a".charCodeAt(0);
function addNextWords(word: string, wordDict: Set<string>, toVisitQueue: string[]): void {
wordDict.delete(word);
let w: number[] = Array.from({ length: word.length }, (_, index: number) => word.charCodeAt(index));
for (let p: number = 0; p < word.length; p++) {
let letter: number = word.charCodeAt(p);
for (let k: number = 0; k < 26; k++) {
w[p] = CODE_LOWER_A + k;
let searchString: string = w.map(c => String.fromCharCode(c)).join("");
if (wordDict.has(searchString)) {
toVisitQueue.push(searchString);
wordDict.delete(searchString);
}
}
w[p] = letter;
}
}
function ladderLength(beginWord: string, endWord: string, wordList: string[]): number {
let dist: number = 2;
let toVisitQueue: string[] = [];
let wordDict: Set<string> = new Set<string>(wordList);
wordDict.add(endWord);
addNextWords(beginWord, wordDict, toVisitQueue);
while (toVisitQueue.length !== 0) {
let num: number = toVisitQueue.length;
for (let i: number = 0; i < num; i++) {
let word: string = toVisitQueue.shift();
if (word === endWord) return dist;
addNextWords(word, wordDict, toVisitQueue);
}
dist++;
}
}
function exec() {
let result: number = ladderLength("hit", "cog", ["hot", "dot", "dog", "lot", "log"]);
let div: HTMLElement = document.createElement("div");
div.innerText = result.toString();
document.body.appendChild(div);
}
exec();
Scala Solution: (One-way BFS)
import scala.collection.mutable.{Queue, Set, StringBuilder}
object Main extends App {
def addNewWords(word: String, wordDict: Set[String], toVisitQueue: Queue[String]): Unit = {
wordDict -= word
val sb = new StringBuilder(word)
(word.zipWithIndex) foreach { case (c0: Char, i: Int) =>
('a' to 'z') foreach { c1 =>
sb(i) = c1
val neighbourWord = sb.toString
if (wordDict.contains(neighbourWord)) {
toVisitQueue.enqueue(neighbourWord);
wordDict -= neighbourWord
}
}
sb(i) = c0
}
}
def ladderLength(beginWord: String, endWord: String, wordList: Seq[String]): Int = {
val wordDict = scala.collection.mutable.Set() ++ (endWord +: wordList)
val toVisitQueue = Queue.empty[String]
var dist = 2
addNewWords(beginWord, wordDict, toVisitQueue)
while (!toVisitQueue.isEmpty) {
(0 until toVisitQueue.length).foreach { _ =>
val word = toVisitQueue.dequeue
if (word == endWord) return dist
addNewWords(word, wordDict, toVisitQueue)
}
dist += 1
}
dist
}
println(ladderLength("hit", "cog", List("hot", "dot", "dog", "lot", "log")))
}
Typescript Solution: (Two-way BFS)
const CODE_LOWER_A: number = "a".charCodeAt(0);
function ladderLength(beginWord: string, endWord: string, wordList: string[]): number {
let wordDict: Set<string> = new Set<string>(wordList);
let beginSet: Set<string> = new Set<string>();
let endSet: Set<string> = new Set<string>();
let visited: Set<string> = new Set<string>();
let len: number = 1;
beginSet.add(beginWord);
endSet.add(endWord);
while(beginSet.size !== 0 && endSet.size !== 0) {
if (beginSet.size > endSet.size) {
let tmp: Set<string> = beginSet;
beginSet = endSet;
endSet = tmp;
}
let neighbours: Set<string> = new Set<string>();
for (let word of Array.from(beginSet)) {
let chs: number[] = Array.from({ length: word.length }, (_, i: number) => word.charCodeAt(i));
for (let i: number = 0; i < chs.length; i++) {
for (let c: number = 0; c < 26; c++) {
let oldChar: number = chs[i];
chs[i] = CODE_LOWER_A + c;
let target: string = chs.map((s: number) => String.fromCharCode(s)).join("");
if (endSet.has(target)) {
return len + 1;
}
if (!visited.has(target) && wordDict.has(target)) {
neighbours.add(target);
visited.add(target);
}
chs[i] = oldChar;
}
}
}
beginSet = neighbours;
len++;
}
return 0;
}
function exec() {
let result: number = ladderLength("hit", "cog", ["hot", "dot", "dog", "lot", "log"]);
let div: HTMLElement = document.createElement("div");
div.innerText = result.toString();
document.body.appendChild(div);
}
exec();
Scala Solution: (Two-way BFS)
import scala.collection.mutable.{Set, StringBuilder}
object Main extends App {
def ladderLength(beginWord: String, endWord: String, wordList: Seq[String]): Int = {
var wordDict = wordList.toSet
var beginSet = Set(beginWord)
var endSet = Set(endWord)
var len = 1
val visited = Set.empty[String]
while (!beginSet.isEmpty && !endSet.isEmpty) {
if (beginSet.size > endSet.size) {
var tmp = beginSet
beginSet = endSet
endSet = tmp
}
val neighbour = Set.empty[String]
beginSet.foreach { word =>
val sb = new StringBuilder(word)
(sb.zipWithIndex) foreach { case (c0: Char, i: Int) =>
('a' to 'z') foreach { c1 =>
sb(i) = c1
val target = sb.toString
if (endSet.contains(target)) {
return len + 1
}
if (!visited.contains(target) && wordDict.contains(target)) {
visited += target
neighbour += target
}
}
sb(i) = c0
}
}
beginSet = neighbour
len += 1
}
len
}
println(ladderLength("hit", "cog", List("hot", "dot", "dog", "lot", "log")))
}
91. Decode Ways
Source: https://leetcode.com/problems/decode-ways/description/
A message containing letters from A-Z is being encoded to numbers using the following mapping:
'A' -> 1
'B' -> 2
...
'Z' -> 26
Given an encoded message containing digits, determine the total number of ways to decode it.
For example, Given encoded message “12”, it could be decoded as “AB” (1 2) or “L” (12).
The number of ways decoding “12” is 2.
Hint:
Use a dp array of size n + 1 to save subproblem solutions. dp[0]
means an empty string will have one way to decode, dp[1]
means the way to decode a string of size 1. I then check one digit and two digit combination and save the results along the way. In the end, dp[n]
will be the end result.
"12":
1 2
12
"126":
1 2 6
12 6
+
1 26
numDecodings("126") = numDecodings("12") + numDecodings("1")
dp[n] = dp[n-1] + d[n-2] if last two digit can form a letter
dp[n] = dp[n-1] if last two digit cannot form a letter
Typescript Solution:
function numDecodings(s: string): number {
if (!s || s.length === 0) return 0;
let dp: number[] = new Array(10).fill(0);
dp[0] = 1;
dp[1] = s[0] !== "0" ? 1 : 0;
for (let i: number = 2; i <= s.length; i++) {
let one: number = +s.substring(i - 1, i);
let two: number = +s.substring(i - 2, i);
if (one >= 1 && one <= 9) {
dp[i] = dp[i - 1];
}
if (two >= 10 && two <= 26) {
dp[i] += dp[i - 2];
}
}
return dp[s.length];
}
function exec() {
let result: number = numDecodings("126");
let div: HTMLElement = document.createElement("div");
div.innerText = result.toString();
document.body.appendChild(div);
}
exec();
Scala Solution:
object Main extends App {
def numDecodings(s: String): Int = {
if (s.isEmpty) 0
else {
val dp = new Array[Int](s.length + 1)
dp(0) = 1
dp(1) = if (s(0) != '0') 1 else 0
for (i <- 2 to s.length) {
val one = s.substring(i - 1, i).toInt
val two = s.substring(i - 2, i).toInt
if (one >= 1 && i <= 9) {
dp(i) = dp(i - 1)
}
if (two >= 10 && two <= 26) {
dp(i) += dp(i - 2)
}
}
dp(s.length)
}
}
println(numDecodings(""))
println(numDecodings("1"))
println(numDecodings("12"))
println(numDecodings("126"))
println(numDecodings("136"))
}
165. Compare Version Numbers
Source: https://leetcode.com/problems/compare-version-numbers/description/
Compare two version numbers version1 and version2. If version1 > version2 return 1, if version1 < version2 return -1, otherwise return 0.
You may assume that the version strings are non-empty and contain only digits and the . character.
The .
character does not represent a decimal point and is used to separate number sequences.
For instance, 2.5
is not “two and a half” or “half way to version three”, it is the fifth second-level revision of the second first-level revision.
Here is an example of version numbers ordering:
0.1 < 1.1 < 1.2 < 13.37
Typescript Solution:
function compareTo(s1: number, s2: number): number {
if (s1 < s2) return -1;
else if (s1 > s2) return 1;
else return 0;
}
function compareVersion(version1: string, version2: string): number {
let levels1: string[] = version1.split('.');
let levels2: string[] = version2.split('.');
let length: number = Math.max(levels1.length, levels2.length);
for (let i: number = 0; i < length; i++) {
let v1: number = i < levels1.length ? +levels1[i] : 0;
let v2: number = i < levels2.length ? +levels2[i] : 0;
let compareResult: number = compareTo(v1, v2);
if (compareResult !== 0) {
return compareResult;
}
}
return 0;
}
function exec() {
let result: number = compareVersion("1.10", "1.2");
let div: HTMLElement = document.createElement("div");
div.innerText = result.toString();
document.body.appendChild(div);
}
exec();
Scala Solution:
object Main extends App {
def compareVersion(version1: String, version2: String): Int = {
val levels1 = version1.split('.')
val levels2 = version2.split('.')
levels1.zipAll(levels2, "0", "0").foldLeft(0) { (result, pair) =>
if (result != 0) result else pair._1.compareTo(pair._2)
}
}
println(compareVersion("1.1.0.0", "1.1"))
}
457. Circular Array Loop
Source: https://leetcode.com/problems/circular-array-loop/description/
You are given an array of positive and negative integers. If a number n at an index is positive, then move forward n steps. Conversely, if it’s negative (-n), move backward n steps. Assume the first element of the array is forward next to the last element, and the last element is backward next to the first element. Determine if there is a loop in this array. A loop starts and ends at a particular index with more than 1 element along the loop. The loop must be “forward” or “backward” .
Example 1: Given the array [2, -1, 1, 2, 2], there is a loop, from index 0 -> 2 -> 3 -> 0.
Example 2: Given the array [-1, 2], there is no loop.
Note: The given array is guaranteed to contain no element “0”.
Can you do it in O(n) time complexity and O(1) space complexity?
Hint:
Slow/Fast Pointer Solution: Just think it as finding a loop in Linked-list, except that loops with only 1 element do not count. Use a slow and fast pointer, slow pointer moves 1 step a time while fast pointer moves 2 steps a time. If there is a loop (fast == slow), we return true, else if we meet element with different directions, then the search fail, we set all elements along the way to 0. Because 0 is fail for sure so when later search meet 0 we know the search will fail.
Typescript Solution:
function circularArrayLoop(nums: number[]): boolean {
let n: number = nums.length;
let arr: number[] = nums.slice(); // Make a copy
const move = (i: number): number => {
return i + nums[i] >= 0 ? (i + nums[i]) % n : (i + nums[i]) % n + n;
}
for (let i: number = 0; i < n; i++) {
if (arr[i] === 0) continue;
// slow / faster pointer
let slow: number = i, fast: number = i;
// Safe to move the slow pointer once and move the fast pointer twice
while (arr[slow] * arr[i] > 0 && arr[fast] * arr[i] > 0 && arr[move(fast)] * arr[i] > 0) {
// Make the move
slow = move(slow);
fast = move(move(fast));
if (slow === fast) { // Encounter each other!
if (slow === move(slow)) break; // 1 element loop is not a valid loop
return true;
}
}
// Optimization: Mark element along the path to be 0
let direction: number = arr[i]; // arr[i] will be set to 0 in first iteration in loop
slow = i;
while (direction * arr[slow] > 0) {
let nextPos: number = move(slow);
arr[slow] = 0;
slow = nextPos;
}
}
return false;
}
function exec() {
let result: boolean = circularArrayLoop([2, -1, 1, 2, 2]);
let div: HTMLElement = document.createElement("div");
div.innerText = result.toString();
document.body.appendChild(div);
}
exec();
Scala Solution:
object Main extends App {
def circularArrayLoop(nums: Array[Int]): Boolean = {
val arr = nums.clone()
val n = nums.size
def move(i: Int) = if (i + arr(i) >= 0) (i + arr(i)) % n else (i + arr(i)) % n + n
def slowFastPointerSearch(i: Int, slow: Int, fast: Int): Boolean = {
if (!(arr(i) * arr(slow) > 0 && arr(i) * arr(fast) > 0 && arr(move(fast)) * arr(i) > 0)) false
else {
val nextSlow = move(slow)
val nextFast = move(move(fast))
if (nextSlow != nextFast) slowFastPointerSearch(i, nextSlow, nextFast)
else if (nextSlow == move(nextSlow)) false
else true
}
}
(0 until n) exists { i =>
if (arr(i) == 0) false
else if (slowFastPointerSearch(i, i, i)) true
else {
// Optimization: Mark element along the path to be 0
val direction = arr(i)
var j = i
while (direction * arr(i) > 0) {
val nextPos = move(j)
arr(j) = 0
j = nextPos
}
false
}
}
}
println(circularArrayLoop(Array(2, -1, 1, 2, 2)))
}
468. Validate IP Address
Source: https://leetcode.com/problems/validate-ip-address/description/
Write a function to check whether an input string is a valid IPv4 address or IPv6 address or neither.
IPv4 addresses are canonically represented in dot-decimal notation, which consists of four decimal numbers, each ranging from 0 to 255, separated by dots (“.”), e.g.,172.16.254.1
;
Besides, leading zeros in the IPv4 is invalid. For example, the address 172.16.254.01
is invalid.
IPv6 addresses are represented as eight groups of four hexadecimal digits, each group representing 16 bits. The groups are separated by colons (“:”). For example, the address 2001:0db8:85a3:0000:0000:8a2e:0370:7334
is a valid one. Also, we could omit some leading zeros among four hexadecimal digits and some low-case characters in the address to upper-case ones, so 2001:db8:85a3:0:0:8A2E:0370:7334
is also a valid IPv6 address(Omit leading zeros and using upper cases).
However, we don’t replace a consecutive group of zero value with a single empty group using two consecutive colons (::) to pursue simplicity. For example, 2001:0db8:85a3::8A2E:0370:7334
is an invalid IPv6 address.
Besides, extra leading zeros in the IPv6 is also invalid. For example, the address 02001:0db8:85a3:0000:0000:8a2e:0370:7334
is invalid.
Note: You may assume there is no extra space or special characters in the input string.
Example 1:
Input: "172.16.254.1"
Output: "IPv4"
Explanation: This is a valid IPv4 address, return "IPv4".
Example 2:
Input: "2001:0db8:85a3:0:0:8A2E:0370:7334"
Output: "IPv6"
Explanation: This is a valid IPv6 address, return "IPv6".
Example 3:
Input: "256.256.256.256"
Output: "Neither"
Explanation: This is neither a IPv4 address nor a IPv6 address.
Typescript Solution:
class IPAddressProcessor {
public static validIPAddress(ip: string): string {
if (IPAddressProcessor.isValidIPv4(ip)) return "IPv4";
else if (IPAddressProcessor.isValidIPv6(ip)) return "IPv6";
else return "Neither";
}
public static isValidIPv4(ip: string): boolean {
if (ip.length < 7) return false; // edge case: 0.0.0.0
if (ip[0] === "." || ip[ip.length - 1] === ".") return false; // edge case: .0.10.0.
let tokens: string[] = ip.split('.');
if (tokens.length !== 4) return false;
return tokens.every(IPAddressProcessor.isValidIPv4Token);
}
public static isValidIPv6(ip: string): boolean {
if (ip.length < 15) return false; // edge case: 0:0:0:0:0:0:0:0
if (ip[0] === ":" || ip[ip.length - 1] === ":") return false;
let tokens: string[] = ip.split(":");
if (tokens.length !== 8) return false;
return tokens.every(IPAddressProcessor.isValidIPv6Token);
}
private static isValidIPv4Token(token: string): boolean {
if (token.length === 0) return false;
if (token[0] === "0" && token.length > 1) return false;
try {
let tokenValue: number = +token;
if (tokenValue < 0 || tokenValue > 255) return false;
if (tokenValue === 0 && token[0] !== "0") return false;
} catch(e) {
return false;
}
return true;
}
private static isValidIPv6Token(token: string): boolean {
if (token.length > 4 || token.length === 0) return false;
const isBase16 = (c: string) => {
return (c >= "0" && c <= "9") // is digit
|| (c >= "a" && c <= "f") // is lower a to f
|| (c >= "A" && c <= "F"); // is uppper a to f
};
return Array.from(token).every(isBase16);
}
}
function exec() {
let result: string = IPAddressProcessor.validIPAddress("2001:db8:85a3:0:0:8A2E:370:7334");
let div: HTMLElement = document.createElement("div");
div.innerText = result;
document.body.appendChild(div);
}
exec();
Scala Solution:
object IPAddressProcessor {
def validIPAddress(ip: String): String = {
if (isValidIPv4(ip)) "IPv4"
else if (isValidIPv6(ip)) "IPv6"
else "Neither"
}
def isValidIPv4(ip: String): Boolean = {
if (ip.length < 7 || ip.head == '.' || ip.last == '.') false
else {
val tokens = ip.split('.')
if (tokens.size != 4) false
else tokens.forall(isValidIPv4Token)
}
}
def isValidIPv6(ip: String): Boolean = {
if (ip.length < 15 || ip.head == ':' || ip.last == ':') false
else {
val tokens = ip.split(':')
if (tokens.size != 8) false
else tokens.forall(isValidIPv6Token)
}
}
private def isValidIPv4Token(token: String): Boolean = {
if (token.isEmpty || token.head == '0' && !token.isEmpty) false
else {
try {
val tokenValue: Int = token.toInt
if (tokenValue < 0 || tokenValue > 255 || tokenValue == 0 && token.length != 1) false
else true
} catch {
case _ => false
}
}
}
private def isValidIPv6Token(token: String): Boolean = {
def isBase16(c: Char) = c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'
if (token.length > 4 || token.isEmpty) false
else token.forall(isBase16)
}
}
object Main extends App {
println(IPAddressProcessor.validIPAddress("172.16.254.1"))
println(IPAddressProcessor.validIPAddress("2001:db8:85a3:0:0:8A2E:0370:7334"))
println(IPAddressProcessor.validIPAddress("255.255.256.255"))
println(IPAddressProcessor.validIPAddress("255.0.01.255"))
println(IPAddressProcessor.validIPAddress("255. 0 .01.255"))
println(IPAddressProcessor.validIPAddress("2001:db8:85a3:::8A2E:0370:7334"))
}
184. Department Highest Salary
Source: https://leetcode.com/problems/department-highest-salary/discuss/
The Employee table holds all employees. Every employee has an Id, a salary, and there is also a column for the department Id.
+----+-------+--------+--------------+
| Id | Name | Salary | DepartmentId |
+----+-------+--------+--------------+
| 1 | Joe | 70000 | 1 |
| 2 | Henry | 80000 | 2 |
| 3 | Sam | 60000 | 2 |
| 4 | Max | 90000 | 1 |
+----+-------+--------+--------------+
The Department table holds all departments of the company.
+----+----------+
| Id | Name |
+----+----------+
| 1 | IT |
| 2 | Sales |
+----+----------+
Write a SQL query to find employees who have the highest salary in each of the departments. For the above tables, Max has the highest salary in the IT department and Henry has the highest salary in the Sales department.
+------------+----------+--------+
| Department | Employee | Salary |
+------------+----------+--------+
| IT | Max | 90000 |
| Sales | Henry | 80000 |
+------------+----------+--------+
SQL Schema
Create table If Not Exists Employee (Id int, Name varchar(255), Salary int, DepartmentId int);
Create table If Not Exists Department (Id int, Name varchar(255));
Truncate table Employee;
insert into Employee (Id, Name, Salary, DepartmentId) values ('1', 'Joe', '70000', '1');
insert into Employee (Id, Name, Salary, DepartmentId) values ('2', 'Henry', '80000', '2');
insert into Employee (Id, Name, Salary, DepartmentId) values ('3', 'Sam', '60000', '2');
insert into Employee (Id, Name, Salary, DepartmentId) values ('4', 'Max', '90000', '1');
Truncate table Department;
insert into Department (Id, Name) values ('1', 'IT');
insert into Department (Id, Name) values ('2', 'Sales');
Solution:
SELECT dep.Name as Department, emp.Name as Employee, emp.Salary
from Department dep, Employee emp
where emp.DepartmentId=dep.Id
and emp.Salary=(Select max(Salary) from Employee e2 where e2.DepartmentId=dep.Id)
177. Nth Highest Salary
Write a SQL query to get the nth highest salary from the Employee table.
+----+--------+
| Id | Salary |
+----+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
+----+--------+
For example, given the above Employee table, the nth highest salary where n = 2 is 200. If there is no nth highest salary, then the query should return null.
+------------------------+
| getNthHighestSalary(2) |
+------------------------+
| 200 |
+------------------------+
Solution:
WITH Unique_Salary AS (SELECT DISTINCT Salary FROM Employee)
SELECT e1.Salary
FROM Unique_Salary e1
WHERE N - 1 =
(SELECT COUNT(*)
FROM Unique_Salary e2
WHERE e2.Salary > e1.Salary)
LIMIT 1
Or use Order By
with Limit N - 1
SELECT IFNULL((SELECT DISTINCT Salary FROM Employee ORDER BY Salary DESC LIMIT N - 1 ,1), NULL)
15. 3Sum
Source: https://leetcode.com/problems/3sum/description/
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note: The solution set must not contain duplicate triplets.
For example, given array S = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
Hint:
The idea is to sort an input array and then run through all indices of a possible first element of a triplet. For each possible first element we make a standard bi-directional 2Sum sweep of the remaining part of the array. Also we want to skip equal elements to avoid duplicates in the answer without making a set or smth like that.
Typescript Solution:
class ThreeSumSolution {
public static threeSum(nums: number[]): [number, number, number][] {
let sorted: number[] = nums.sort();
let result: [number, number, number][] = [];
for (let i: number = 0; i < sorted.length - 2; i++) {
if (i === 0 || i > 0 && sorted[i] !== sorted[i-1]) { // skip the term that has same value
ThreeSumSolution.twoSum(sorted, i, result);
}
}
return result;
}
private static twoSum(sorted: number[], i: number, output: [number, number, number][]): void {
let lo: number = i + 1, hi: number = sorted.length - 1, sum: number = 0 - sorted[i];
while (lo < hi) {
if (sorted[lo] + sorted[hi] === sum) {
output.push([sorted[i], sorted[lo], sorted[hi]]);
while (lo < hi && sorted[lo] === sorted[lo + 1]) lo++;
while (lo < hi && sorted[hi] === sorted[hi - 1]) hi--;
lo++; hi--;
} else if (sorted[lo] + sorted[hi] < sum) lo++;
else hi--;
}
}
}
function exec() {
let result: [number, number, number][] = ThreeSumSolution.threeSum([-1, 0, 1, 2, -1, -4]);
let div: HTMLElement = document.createElement("div");
div.innerText = result.toString();
document.body.appendChild(div);
}
exec();
Scala Solution:
object ThreeSumSolution {
def threeSum(nums: IndexedSeq[Int]): Seq[(Int, Int, Int)] = {
val sorted = nums.sorted
var result = List.empty[(Int, Int, Int)]
for (i <- 0 until sorted.size - 2) {
if (i == 0 || i > 0 && sorted(i) != sorted(i - 1)) {
var lo = i + 1
var hi = sorted.size - 1
var sum = 0 - sorted(i)
while (lo < hi) {
if (sorted(lo) + sorted(hi) == sum) {
result = (sorted(i), sorted(lo), sorted(hi)) :: result
while (lo < hi && sorted(lo) == sorted(lo + 1)) lo += 1
while (lo < hi && sorted(hi) == sorted(hi - 1)) hi -= 1
lo += 1
hi -= 1
} else if (sorted(lo) + sorted(hi) < sum) {
lo += 1
} else {
hi -= 1
}
}
}
}
result
}
}
object Main extends App {
println(ThreeSumSolution.threeSum(Array(-1, 0, 1, 2, -1, -4)))
}
307. Range Sum Query - Mutable
Sourece: https://leetcode.com/problems/range-sum-query-mutable/description/
Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.
The update(i, val) function modifies nums by updating the element at index i to val.
Example:
Given nums = [1, 3, 5]
sumRange(0, 2) -> 9
update(1, 2)
sumRange(0, 2) -> 8
Note:
- The array is only modifiable by the update function.
- You may assume the number of calls to update and sumRange function is distributed evenly.
Approach #1 Sqrt decomposition
class NumArray(private val nums: Array[Int]) {
val (block, blockSize) = initBlock()
def update(i: Int, value: Int): Unit = {
val blockIndex = i / blockSize
block(blockIndex) += value - nums(i)
nums(i) = value
}
def sumRange(i: Int, j: Int): Int = {
var sum = 0
var startBlock = i / blockSize
var endBlock = j / blockSize
if (startBlock == endBlock) { // within the same block
for (k <- i to j) sum += nums(k)
} else {
for (k <- i to (startBlock + 1) * blockSize - 1) sum += nums(k)
for (k <- (startBlock + 1) to (endBlock - 1)) sum += block(k)
for (k <- (endBlock * blockSize) to j) sum += nums(k)
}
sum
}
private def initBlock(): (Array[Int], Int) = {
val blockSize = Math.ceil(Math.sqrt(nums.size)).toInt
val block = new Array[Int](blockSize)
for (i <- 0 until nums.size) {
block(i / blockSize) += nums(i)
}
(block, blockSize)
}
}
object Main extends App {
val obj = new NumArray(Array(1, 3, 5))
println(obj.sumRange(0, 2)) // 9
obj.update(1, 2)
println(obj.sumRange(0, 2)) // 8
}
Approach #2: Segment tree
class NumArray(private val nums: Array[Int]) {
private val tree = buildTree()
def update(i: Int, value: Int): Unit = {
// update the leaf node and roll value all the way up to root
var pos = i + nums.size
tree(pos) = value
while (pos > 0) {
var left = pos
var right = pos
if (pos % 2 == 0) right = pos + 1 // pos is left child
else left = pos - 1 // pos is right child
// parent is updated after child is updated
tree(pos / 2) = tree(left) + tree(right)
pos /= 2
}
}
def sumRange(i: Int, j: Int): Int = {
val n = nums.size
var l = i + n
var r = j + n
var sum = 0
while (l <= r) {
// 1~7
// / \
// / \
// 1~3 4~7
// / \ / \
// 1 2~3 4~5 6~7
// / | | | / \
// 2 3 4 5 6 7
// case1: suppose l is right child that represents 2~3, we sum value(2~3) then move l right to 4~5
// case2: suppose l is left child do nothing
if (l % 2 == 1) { // l bound is right child
sum += tree(l)
l += 1
}
// case3: suppose r is right child that represents 6~7, do nothing
// case4: suppose r is left child that represents 4~5, we sum value(4~5) then move r left to 2~3
if ((r % 2) == 0) { // r bound is left child
sum += tree(r)
r -= 1
}
// Mov l and r to parent and continue
l /= 2
r /= 2
}
sum
}
private def buildTree(): Array[Int] = {
if (nums.isEmpty) Array.empty[Int]
else {
val n = nums.size
val tree = new Array[Int](2 * n)
for (i <- 0 until n) {
tree(n + i) = nums(i)
}
for (i <- n - 1 until 0 by -1) {
tree(i) = tree(i * 2) + tree(i * 2 + 1)
}
tree
}
}
}
object Main extends App {
val obj = new NumArray(Array(1, 3, 5))
println(obj.sumRange(0, 2)) // 9
obj.update(1, 2)
println(obj.sumRange(0, 2)) // 8
}
Apparoach #3 BIT or Fenwick tree
public class NumArray {
/**
* Binary Indexed Trees (BIT or Fenwick tree):
* https://www.topcoder.com/community/data-science/data-science-
* tutorials/binary-indexed-trees/
*
* Example: given an array a[0]...a[7], we use a array BIT[9] to
* represent a tree, where index [2] is the parent of [1] and [3], [6]
* is the parent of [5] and [7], [4] is the parent of [2] and [6], and
* [8] is the parent of [4]. I.e.,
*
* BIT[] as a binary tree:
* ______________*
* ______*
* __* __*
* * * * *
* indices: 0 1 2 3 4 5 6 7 8
*
* BIT[i] = ([i] is a left child) ? the partial sum from its left most
* descendant to itself : the partial sum from its parent (exclusive) to
* itself. (check the range of "__").
*
* Eg. BIT[1]=a[0], BIT[2]=a[1]+BIT[1]=a[1]+a[0], BIT[3]=a[2],
* BIT[4]=a[3]+BIT[3]+BIT[2]=a[3]+a[2]+a[1]+a[0],
* BIT[6]=a[5]+BIT[5]=a[5]+a[4],
* BIT[8]=a[7]+BIT[7]+BIT[6]+BIT[4]=a[7]+a[6]+...+a[0], ...
*
* Thus, to update a[1]=BIT[2], we shall update BIT[2], BIT[4], BIT[8],
* i.e., for current [i], the next update [j] is j=i+(i&-i) //double the
* last 1-bit from [i].
*
* Similarly, to get the partial sum up to a[6]=BIT[7], we shall get the
* sum of BIT[7], BIT[6], BIT[4], i.e., for current [i], the next
* summand [j] is j=i-(i&-i) // delete the last 1-bit from [i].
*
* To obtain the original value of a[7] (corresponding to index [8] of
* BIT), we have to subtract BIT[7], BIT[6], BIT[4] from BIT[8], i.e.,
* starting from [idx-1], for current [i], the next subtrahend [j] is
* j=i-(i&-i), up to j==idx-(idx&-idx) exclusive. (However, a quicker
* way but using extra space is to store the original array.)
*/
int[] nums;
int[] BIT;
int n;
public NumArray(int[] nums) {
this.nums = nums;
n = nums.length;
BIT = new int[n + 1];
for (int i = 0; i < n; i++)
init(i, nums[i]);
}
public void init(int i, int val) {
i++;
while (i <= n) {
BIT[i] += val;
i += (i & -i);
}
}
void update(int i, int val) {
int diff = val - nums[i];
nums[i] = val;
init(i, diff);
}
public int getSum(int i) {
int sum = 0;
i++;
while (i > 0) {
sum += BIT[i];
i -= (i & -i);
}
return sum;
}
public int sumRange(int i, int j) {
return getSum(j) - getSum(i - 1);
}
}
// Your NumArray object will be instantiated and called as such:
// NumArray numArray = new NumArray(nums);
// numArray.sumRange(0, 1);
// numArray.update(1, 10);
// numArray.sumRange(1, 2);
Q & A:
What are differences between segment trees, interval trees, binary indexed trees and range trees in terms of:
- Key idea/definition
- Applications
- Performance/order in higher dimensions/space consumption
Answer:
All these data structures are used for solving different problems:
- Segment tree stores intervals, and optimized for “which of these intervals contains a given point” queries. (It is a static structure; that is, it’s a structure that cannot be modified once it’s built, same as interval tree.)
- Interval tree stores intervals as well, but optimized for “which of these intervals overlap with a given interval” queries. It can also be used for point queries - similar to segment tree.
- Range tree stores points, and optimized for “which points fall within a given interval” queries.
- Binary indexed tree stores items-count per index, and optimized for “how many items are there between index m and n” queries.
One Dimension
k
is the number of reported results
| Segment | Interval | Range | Indexed | --------------|--------------:|-----------:|---------------:|----------:| Preprocessing | n logn | n logn | n logn | n logn | Query | k+logn | k+logn | k+logn | logn | Space | n | n | n | n | Insert/Delete | logn | logn | logn | logn |
Higher Dimensions
d > 1
| Segment | Interval | Range | Indexed | --------------|--------------:|-----------:|---------------:|----------:| Preprocessing | n(logn)^d | n logn | n(logn)^d | n(logn)^d | Query | k+(logn)^d | k+(logn)^d | k+(logn)^d | (logn)^d | Space | n(logn)^(d-1) | n logn | n(logn)^(d-1)) | n(logn)^d |
54. Spiral Matrix
Source: https://leetcode.com/problems/spiral-matrix/description/
Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.
For example, Given the following matrix:
[
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
]
You should return [1,2,3,6,9,8,7,4,5]
.
Hint:
This is a very simple and easy to understand solution. I traverse right and increment rowBegin, then traverse down and decrement colEnd, then I traverse left and decrement rowEnd, and finally I traverse up and increment colBegin.
The only tricky part is that when I traverse left or up I have to check whether the row or col still exists to prevent duplicates.
Solution
public class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res = new ArrayList<Integer>();
if (matrix.length == 0) {
return res;
}
int rowBegin = 0;
int rowEnd = matrix.length-1;
int colBegin = 0;
int colEnd = matrix[0].length - 1;
while (rowBegin <= rowEnd && colBegin <= colEnd) {
// Traverse Right
for (int j = colBegin; j <= colEnd; j ++) {
res.add(matrix[rowBegin][j]);
}
rowBegin++;
// Traverse Down
for (int j = rowBegin; j <= rowEnd; j ++) {
res.add(matrix[j][colEnd]);
}
colEnd--;
if (rowBegin <= rowEnd) {
// Traverse Left
for (int j = colEnd; j >= colBegin; j --) {
res.add(matrix[rowEnd][j]);
}
}
rowEnd--;
if (colBegin <= colEnd) {
// Traver Up
for (int j = rowEnd; j >= rowBegin; j --) {
res.add(matrix[j][colBegin]);
}
}
colBegin ++;
}
return res;
}
}
40. Combination Sum II
Source: https://leetcode.com/problems/combination-sum-ii/description/
Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
Each number in C may only be used once in the combination.
Note:
- All numbers (including target) will be positive integers.
- The solution set must not contain duplicate combinations.
- For example, given candidate set
[10, 1, 2, 7, 6, 1, 5]
and target8
, A solution set is:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
Solution
public List<List<Integer>> combinationSum2(int[] cand, int target) {
Arrays.sort(cand);
List<List<Integer>> res = new ArrayList<List<Integer>>();
List<Integer> path = new ArrayList<Integer>();
dfs_com(cand, 0, target, path, res);
return res;
}
void dfs_com(int[] cand, int cur, int target, List<Integer> path, List<List<Integer>> res) {
if (target == 0) {
res.add(new ArrayList(path));
return ;
}
if (target < 0) return;
for (int i = cur; i < cand.length; i++){
if (i > cur && cand[i] == cand[i-1]) continue;
path.add(path.size(), cand[i]);
dfs_com(cand, i+1, target - cand[i], path, res);
path.remove(path.size()-1);
}
}
114. Flatten Binary Tree to Linked List
Source: https://leetcode.com/problems/flatten-binary-tree-to-linked-list/description/
Given a binary tree, flatten it to a linked list in-place.
For example, Given
1
/ \
2 5
/ \ \
3 4 6
The flattened tree should look like:
1
\
2
\
3
\
4
\
5
\
6
Hints:
If you notice carefully in the flattened tree, each node’s right child points to the next node of a pre-order traversal.
Solution1:
private TreeNode prev = null;
public void flatten(TreeNode root) {
if (root == null)
return;
flatten(root.right);
flatten(root.left);
root.right = prev;
root.left = null;
prev = root;
}
Solution2:
public class Solution {
public void flatten(TreeNode root) {
if (root == null) {
return;
}
if (root.left == null && root.right == null) {
return;
}
while (root != null) {
if (root.left == null) {
root = root.right;
continue;
}
TreeNode left = root.left;
while (left.right != null) {
left = left.right;
}
left.right = root.right;
root.right = root.left;
root.left = null;
root = root.right;
}
}
}