The k-th Lexicographical String of All Happy Strings of Length n

medium backtracking counting

Problem

A happy string uses only the letters a, b, c and never repeats a letter in two adjacent positions. Imagine every happy string of length n written out in alphabetical (lexicographical) order.

Given n and k (1 ≤ n ≤ 10, 1 ≤ k ≤ 100), return the k-th string in that sorted list, or the empty string if the list contains fewer than k strings.

Inputn = 3, k = 9
Output"cab"
The 12 happy strings of length 3 are aba, abc, aca, acb, bab, bac, bca, bcb, cab, cac, cba, cbc — the 9th is "cab".

def get_happy_string(n, k):
    total = 3 * (1 << (n - 1))      # happy strings of length n
    if k > total:
        return ""                       # list is too short
    k -= 1                              # 0-based leaf index
    res = []
    for i in range(n):
        block = 1 << (n - 1 - i)    # leaves under each choice here
        for c in "abc":
            if res and res[-1] == c:
                continue                # would repeat previous letter
            if k < block:
                res.append(c)           # target leaf is in this subtree
                break
            k -= block                  # skip this whole subtree
    return "".join(res)
function getHappyString(n, k) {
  const total = 3 * (1 << (n - 1)); // happy strings of length n
  if (k > total) return "";
  k -= 1;                              // 0-based leaf index
  let res = "";
  for (let i = 0; i < n; i++) {
    const block = 1 << (n - 1 - i); // leaves under each choice here
    for (const c of "abc") {
      if (res.endsWith(c)) continue;        // would repeat previous letter
      if (k < block) { res += c; break; }  // target is in this subtree
      k -= block;                           // skip this whole subtree
    }
  }
  return res;
}
String getHappyString(int n, int k) {
    int total = 3 * (1 << (n - 1));      // happy strings of length n
    if (k > total) return "";
    k -= 1;                                  // 0-based leaf index
    StringBuilder res = new StringBuilder();
    for (int i = 0; i < n; i++) {
        int block = 1 << (n - 1 - i);    // leaves under each choice here
        for (char c = 'a'; c <= 'c'; c++) {
            if (i > 0 && res.charAt(i - 1) == c) continue;
            if (k < block) { res.append(c); break; }
            k -= block;                      // skip this whole subtree
        }
    }
    return res.toString();
}
string getHappyString(int n, int k) {
    int total = 3 * (1 << (n - 1));      // happy strings of length n
    if (k > total) return "";
    k -= 1;                                  // 0-based leaf index
    string res;
    for (int i = 0; i < n; i++) {
        int block = 1 << (n - 1 - i);    // leaves under each choice here
        for (char c = 'a'; c <= 'c'; c++) {
            if (!res.empty() && res.back() == c) continue;
            if (k < block) { res += c; break; }
            k -= block;                      // skip this whole subtree
        }
    }
    return res;
}
Time: O(n) Space: O(n)