Absolute Permutation (from HackerRank)

This was a fun, moderate problem: https://www.hackerrank.com/challenges/absolute-permutation
It is asking you to find an absolute permutation for the given arrays. All you have to do is check whether you can find a suitable candidate for each position in the array. There are only two candidates: index+k and index-k. Keep track of the candidates already used, make sure to prioritize the ones in ascending order, and you should be good. It is in linear time, and given the upper bound of 10^5, this would have been a hint that you need to do it in linear time otherwise the TCs will timeout. Apparently it worked:


Code is below, cheers, Marcelo.

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Collections;
class Solution
{
    public static void Main(String[] args)
    {
        int t = Int32.Parse(Console.ReadLine());
        int[][] solution = new int[t][];

        for (int i = 0; i < t; i++)
        {
            string[] parts = Console.ReadLine().Split(' ');
            int n = Int32.Parse(parts[0]);
            int k = Int32.Parse(parts[1]);

            solution[i] = new int[n];

            Hashtable htUsed = new Hashtable();
            for (int j = 0; j < n; j++)
            {
                int index = j + 1;
                int candidate1 = index + k;
                int candidate2 = index - k;

                if (candidate1 > 0 &&
                    candidate1 <= n &&
                    !htUsed.ContainsKey(candidate1))
                {
                    if (candidate2 <= 0 ||
                        candidate2 > n ||
                        htUsed.ContainsKey(candidate2))
                    {
                        solution[i][j] = candidate1;
                        htUsed.Add(candidate1, true);
                    }
                    else
                    {
                        if (candidate1 < candidate2)
                        {
                            solution[i][j] = candidate1;
                            htUsed.Add(candidate1, true);
                        }
                        else
                        {
                            solution[i][j] = candidate2;
                            htUsed.Add(candidate2, true);
                        }
                    }
                }
                else if (candidate2 > 0 &&
                         candidate2 <= n &&
                         !htUsed.ContainsKey(candidate2))
                {
                    if (candidate1 <= 0 ||
                        candidate1 > n ||
                        htUsed.ContainsKey(candidate1))
                    {
                        solution[i][j] = candidate2;
                        htUsed.Add(candidate2, true);
                    }
                    else
                    {
                        if (candidate2 < candidate1)
                        {
                            solution[i][j] = candidate2;
                            htUsed.Add(candidate2, true);
                        }
                        else
                        {
                            solution[i][j] = candidate1;
                            htUsed.Add(candidate1, true);
                        }
                    }
                }
                else
                {
                    solution[i] = new int[1];
                    solution[i][0] = -1;
                    break;
                }
            }
        }

        for (int i = 0; i < t; i++)
        {
            for (int j = 0; j < solution[i].Length; j++)
            {
                Console.Write("{0} ", solution[i][j]);
            }
            Console.WriteLine();
        }
    }
}

Comments

  1. I'm not sure why this problem was marked as medium, since it required only a very basic math and coding, but it's still a nice little problem. My solution is pretty much the same, except that I didn't want to accumulate as much memory (storing the entire grid can be pretty expensive in terms of memory) and used a bitset instead of hashtable for checking used values, since most of the time it's going to be full anyways, so hashtable only adds performance and memory overhead :)

    #include
    #include
    #include
    using namespace std;

    int value_at(int i, int k, const vector used) {
    // abs(x - i) = k:
    // 1) x - i = k => x = k + i
    // 2) x - i = -k => x = -k + i
    int case_2 = -k + i;
    // case 2 is preferable (smaller) as long as it's still unused
    if (case_2 > 0 && !used[case_2]) return case_2;
    return k + i; // case 1
    }

    vector permutation_for(int K, int N) {
    vector permutation(N);
    vector used(N+1, false);
    for (int i = 1; i <= N; ++i) {
    int value = value_at(i, K, used);
    if (value > N || used[value]) return {};
    permutation[i-1] = value;
    used[value] = true;
    }
    return permutation;
    }

    int main() {
    int T; cin >> T;
    for (int t = 0; t < T; ++t) {
    int N, K; cin >> N >> K;
    vector permutation = permutation_for(K, N);
    if (permutation.empty()) {
    cout << "-1";
    } else {
    copy(permutation.cbegin(), permutation.cend(), ostream_iterator(cout, " "));
    }
    cout << endl;
    }
    return 0;
    }

    Cheers,
    Taras

    ReplyDelete

Post a Comment

Popular posts from this blog

Advent of Code - Day 6, 2024: BFS and FSM

Golang vs. C#: performance characteristics (simple case study)

Advent of Code - Day 7, 2024: Backtracking and Eval