667. Beautiful Arrangement II

Description

Given two integers n and k, you need to construct a list which contains n different positive integers ranging from 1 to n and obeys the following requirement:
Suppose this list is [a1, a2, a3, ... , an], then the list [|a1 - a2|, |a2 - a3|, |a3 - a4|, ... , |an-1 - an|] has exactly k distinct integers.

If there are multiple answers, print any of them.

Example 1:

Input: n = 3, k = 1
Output: [1, 2, 3]
Explanation: The [1, 2, 3] has three different positive integers ranging from 1 to 3, and the [1, 1] has exactly 1 distinct integer: 1.

Example 2:

Input: n = 3, k = 2
Output: [1, 3, 2]
Explanation: The [1, 3, 2] has three different positive integers ranging from 1 to 3, and the [2, 1] has exactly 2 distinct integers: 1 and 2.

Note:

  1. The n and k are in the range 1 <= k < n <= 104.

Solution

Backtracking, O(n ^ 2), S(n) (TLE)

典型的回溯思路。

class Solution {
    public int[] constructArray(int n, int k) {
        int[] nums = new int[n];
        for (int i = 0; i < n; ++i) {
            nums[i] = i + 1;
        }
        backtracking(nums, 0, new int[n], 0, k);
        return nums;
    }
    
    private boolean backtracking(int[] nums, int start, int[] counts, int unique, int k) {
        if (start >= nums.length && unique == k) {
            return true;
        }
        
        if (unique >= k) {
            return false;
        }
        
        for (int i = start; i < nums.length; ++i) {
            swap(nums, start, i);
            
            if (start > 0) {
                int delta = Math.abs(nums[start] - nums[start - 1]);
                if (++counts[delta] == 1) {
                    ++unique;
                }
            }
            
            if (backtracking(nums, start + 1, counts, unique, k)) {
                return true;
            }
            
            if (start > 0) {
                int delta = Math.abs(nums[start] - nums[start - 1]);
                if (--counts[delta] == 0) {
                    --unique;
                }
            }
            swap(nums, start, i);
        }
        
        return false;
    }
    
    private void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

Construct, O(n), S(1)

这道题的解法其实是有规律可循的:

  • k = 1: 序列为{1, 2, ..., n - 1, n}
  • k = n - 1: 序列为{1, n, 2, n - 1, ..., n / 2 - 1, n / 2},这样delta就是{n-1, n-2, n-3, ..., 1},unique count = n - 1
    对n个数字来说,可以构成最少1个最多n - 1个unique delta的序列。

那么如果想要生成unique number为k的n个数序列,把数字分成两部分即可:

  • part 1: n - k - 1个数字:{1, 2, ..., n - k - 1}
  • part 2: k + 1个数字:{1, k, 2, k - 1, ..., k / 2 - 1, k / 2},所有数字再加上初始的increase为n - k - 1。这部分序列生成,要依靠头尾拼接数组来做。

然后将两部分拼接起来,返回即可。

class Solution {
    public int[] constructArray(int n, int k) {
        int[] nums = new int[n];
        int pos = 0;
        
        for (int i = 1; i < n - k; ++i) {
            nums[pos++] = i;
        }
        
        for (int i = 0; i <= k; ++i) {
            nums[pos++] = i % 2 == 0 ?
                i / 2 + n - k : n - i / 2;
        }
        
        return nums;
    }
}

你可能感兴趣的:(667. Beautiful Arrangement II)