Welcome to Subscribe On Youtube

3518. Smallest Palindromic Rearrangement II

Description

You are given a palindromic string s and an integer k.

Return the k-th lexicographically smallest palindromic permutation of s. If there are fewer than k distinct palindromic permutations, return an empty string.

Note: Different rearrangements that yield the same palindromic string are considered identical and are counted once.

 

Example 1:

Input: s = "abba", k = 2

Output: "baab"

Explanation:

  • The two distinct palindromic rearrangements of "abba" are "abba" and "baab".
  • Lexicographically, "abba" comes before "baab". Since k = 2, the output is "baab".

Example 2:

Input: s = "aa", k = 2

Output: ""

Explanation:

  • There is only one palindromic rearrangement: "aa".
  • The output is an empty string since k = 2 exceeds the number of possible rearrangements.

Example 3:

Input: s = "bacab", k = 1

Output: "abcba"

Explanation:

  • The two distinct palindromic rearrangements of "bacab" are "abcba" and "bacab".
  • Lexicographically, "abcba" comes before "bacab". Since k = 1, the output is "abcba".

 

Constraints:

  • 1 <= s.length <= 104
  • s consists of lowercase English letters.
  • s is guaranteed to be palindromic.
  • 1 <= k <= 106

Solutions

Solution 1

  • impl Solution {
        pub fn smallest_palindrome(s: String, k: i32) -> String {
            let bytes = s.as_bytes();
            let rank = k.max(1) as usize;
            const COUNT_LIMIT: usize = 1_000_001;
            let mut frequencies = [0usize; 26];
            for &byte in bytes {
                frequencies[(byte - b'a') as usize] += 1;
            }
            let mut odd_count = 0usize;
            let mut middle_char_index = 26u8;
            for char_index in 0..26 {
                if frequencies[char_index] & 1 == 1 {
                    odd_count += 1;
                    middle_char_index = char_index as u8;
                }
            }
            if odd_count > 1 {
                return String::new();
            }
            let mut half_frequencies = [0usize; 26];
            let mut half_length = 0usize;
            for char_index in 0..26 {
                half_frequencies[char_index] = frequencies[char_index] / 2;
                half_length += half_frequencies[char_index];
            }
            let count_permutations = |counts: &[usize; 26]| -> usize {
                let mut remaining: usize = counts.iter().sum();
                let mut permutations = 1usize;
                for &count in counts {
                    if count == 0 {
                        continue;
                    }
                    let selected = count.min(remaining - count);
                    let mut combinations = 1usize;
                    for step in 1..=selected {
                        combinations = combinations * (remaining - step + 1) / step;
                        if combinations >= COUNT_LIMIT {
                            combinations = COUNT_LIMIT;
                            break;
                        }
                    }
                    permutations *= combinations;
                    if permutations >= COUNT_LIMIT {
                        return COUNT_LIMIT;
                    }
                    remaining -= count;
                }
                permutations
            };
            if rank > count_permutations(&half_frequencies) {
                return String::new();
            }
            let length = bytes.len();
            let mut palindrome = vec![0u8; length];
            let mut remaining_rank = rank;
            let mut position = 0usize;
            for _ in 0..half_length {
                for char_index in 0..26 {
                    if half_frequencies[char_index] == 0 {
                        continue;
                    }
                    half_frequencies[char_index] -= 1;
                    let suffix_count = count_permutations(&half_frequencies);
                    if suffix_count >= remaining_rank {
                        palindrome[position] = char_index as u8 + b'a';
                        position += 1;
                        break;
                    }
                    remaining_rank -= suffix_count;
                    half_frequencies[char_index] += 1;
                }
            }
            if middle_char_index < 26 {
                palindrome[half_length] = middle_char_index + b'a';
            }
            for index in 0..half_length {
                palindrome[length - 1 - index] = palindrome[index];
            }
            String::from_utf8(palindrome).unwrap()
        }
    }
    
    

All Problems

All Solutions