667 是很坑爹的一个题目,乍一看和 526 如出一辙,

526. Beautiful Arrangement 题意: 构造 [1,n]的排列,让每个 a[index] % index ==0 或者 index %a[index] ==0,  基本和 46 题一样,就是构造排列。

667题意: 

给定两个整数nk,构建一个n个元素数组,数组要满足一下要求: 
假设数组[a1,a2....an]那么[|a2-a1|,|a3-a2|.....]包含k个不同的整数。如果有多个数组输出任意一个数组。1<=k<n<=10000

看到题目误以为和526 类似, 准备用back tracking 构造, 但复杂度为 n! , 如果数据范围为 1000, 那么 1000! 不管如何剪枝,都会TLE,TLE的code 如下,写的竟然有板有眼。

class Solution {
    public int[] constructArray(int n, int k) {
          if(n-1<k) return new int[0];
        
          int[] nums = new int[n];
          List<Integer> result = new ArrayList<>();
          for(int i=0; i<n; i++){
              nums[i] = i+1;
          }
          dfs(result, nums, new boolean[n], k, new HashSet<>());
          
          for(int i=0; i<result.size(); i++) nums[i] = result.get(i);
          return nums;
    }
    
    private boolean dfs(List<Integer> result, int[] nums, boolean[] used, int k , Set<Integer> set){
        if(result.size() == nums.length && set.size() == k){
            System.out.println(result);
            return true;
        }
        
        if(result.size() >= nums.length) return false;
        
        boolean flag = false;
        for(int i=0; i<nums.length; i++){
            if(!used[i]){
                int size = result.size();
                int abs = 0;
                boolean added = false;
                if(result.size()>0){
                    abs = Math.abs(result.get(size-1) - nums[i]);
                    if(!set.contains(abs) && set.size()+1 >k) { continue;} 
                    set.add(abs);
                    added = true;
                     
                }
                result.add(nums[i]);
                used[i] = true;
                flag = flag || dfs(result,nums,used,k,set);
                if(flag) return true;
                result.remove(result.size()-1);
                used[i] = false;
                if(added) set.remove(abs);
            }
        }
        return flag;
    }
}

 

仔细分析一下题目, n 个数 可以排不同差值的组合, 最大 n-1, 最小为1, 所以范围为 [1~n-1], 如果 K > N-1 显然不可解。

比如 n=9, k=5

可以构造  :  1,9,2,8, + 3,4,5,6,7

n=9,k=4, 可以构造: 1,9,2 + [8,7,6,5,4,3]

假设 left = 1, right = n 

对于 K , 可以先放k-1 个数来构造,  1,n,2,n-1。。。 , 剩下的数字 递增或者递减即可

观察上面的case 可以得出 k为odd 时, 接下来 数字为 从left 递增, k为even 时,接下来数字为从right 递减,code 如下, 复杂度为 o(n):

class Solution {
    public int[] constructArray(int n, int k) {
        if(k>n-1) return null;
        int[] result = new int[n];
        int left =1;
        int right = n;
     
        int cons = k-1;
        for(int i=0;i<n; i++){
          if(cons>=0){
              if(i%2 ==0) result[i] = right--;
              else result[i] = left++;
              cons--;
          }
          else {
              if(k%2==0) {
                  result[i] = left++;
              }
              else result[i] = right--;
          }  
        }
      return result;  
    }
}

 

posted on 2018-11-16 12:31  KeepAC  阅读(118)  评论(0编辑  收藏  举报