【每周一算】根据上排给出十个数,在其下排填出对应的十个数

说是一面试题,原题如下:

给你10分钟时间,根据上排给出十个数,在其下排填出对应的十个数   
要求下排每个数都是先前上排那十个数在下排出现的次数。   
上排的十个数如下:   
【0,1,2,3,4,5,6,7,8,9】

举一个例子,   
数值: 0,1,2,3,4,5,6,7,8,9   
结果: 6,2,1,0,0,0,1,0,0,0 

我这里做一个扩展,给出上排一组数字,得出下排对应个数的数字,要求下排每个数都是上排每个数在下排出现的次数。

解题:

1、下排所有的数字之和等于所有数字的个数,因为是出现的次数,且每个数都  >= 0;

2、当上排数字没有0时,下排所有数字都为 0 。是唯一的解法(目前还没有找到更多的解法);

3、不是所有的一排数字都有解

当然还有其它特点,根据这几个特点,写了个解法:

package com.jandmin.demo.leetcode;

import com.alibaba.fastjson.JSON;

/**
 * @description:
 *      根据上排给出的一排数字,在其下排填出对应的个数的数字,
 *      要求下排每个数都是先前上排每个数在下排出现的次数。
 * @author: JandMin
 **/
public class BottomIsUpTimes {
    /**
     * 初始化数组:不可重复
     * @param len 数组长度
     * @param begin 数组的初始值
     * @return
     */
    private static int[] init(int len,int begin) {
        int[] up = new int[len];
        for(int i=0; i<len; i++){
            up[i] = begin + i;
        }
        return up;
    }

    public static void main(String[] args) {
        // 数组最大长度,这里为了测试,多用了几个
        int length = 11;
        // 数组的初始值:可以是负数
        int begin = 0;

        for(int len=2; len < length; len++ ) {
            // 初始化数组
            int[] up = init(len, begin);
            System.out.println(" begin:" + JSON.toJSONString(up));

            // 假设初始结果都是 0
            int[] bottom = new int[len];

            // 根据前一个数组计算结果
            int[] result = countUpArrayTimes(up, bottom, len);
            System.out.println("result:" + JSON.toJSONString(result));
            System.out.println();
        }
    }

    /**
     * 计算上一个数组在下一个数组中出现的次数
     * @param upArray 已知的前一个数组
     * @param bottom 结果数组
     * @param len 数组长度
     * @return
     */
    private static int[] countUpArrayTimes(int[] upArray, int[] bottom, int len) {
        // 获取 0 的位置
        Integer zeroIndex = getIndex(upArray, len,0);
        if(null == zeroIndex){
            // 如果数组中不存在0,那结果数组的所有元素都为0
            return bottom;
        }

        // 从 0 开始计算,假设所有都是 0,然后以 0 的数量依次减少来遍历
        int num = count(bottom, 0, len);
        for (int n=num; n>0; n--) {
            int[] temp = bottom.clone();
            temp[zeroIndex] = n;

            // n 在数组中的位置对应在 结果集中出现的次数
            temp = update(upArray, temp, n, len,0);
            if (null != temp) {
                return temp;
            }
        }
        return null;
    }

    /**
     * 根据 num 在数组中的位置,修改结果集中对应的数量
     * @param array 初始数组
     * @param result 结果数组
     * @param num 数组中的元素
     * @param len 长度
     * @param count 统计循环的次数,防止死循环,如果已经遍历超过了 len 说明次数不符合要求,重新设置 0 的次数
     * @return 返回结果,不符合要求则直接返回 null,重新新一轮的计算
     */
    private static int[] update(int[] array, int[] result, int num, int len,int count) {
        for (int i=0; i<len; i++){
            if(array[i] == num){
                int times = count(result, num, len);

                // 如果num出现的次数正好等于当前元素,次数加1
                if(times == num){
                    times += 1;
                }
                result[i] = times;

                // 结果数组所以值的和 等于数组长度
                int sum = sum(result);
                if(sum > len) {
                    return null;
                }

                // 如果已经符合则返回
                if(check(array,result,len) && sum == len){
                    return result;
                }

                // 防止死循环
                if(count > len){
                    return null;
                }

                // 继续对新出现的数字进行统计
                return update(array,result,times,len,++count);
            }
        }
        return null;
    }

    /**
     * 检查结果数组是否满足条件:要求结果集中的每个数都是原数组每个数在结果集中出现的次数
     * @param array 原数组
     * @param result 结果集
     * @param len 长度
     * @return
     */
    private static boolean check(int[] array, int[] result,int len) {
        for (int i=0; i<len; i++){
            int n = count(result, array[i], len);
            if(n != result[i]){
               return false;
            }
        }
        return true;
    }

    /**
     * 统计结果数组的和
     * @param array
     * @return
     */
    private static int sum(int[] array) {
        int sum = 0;
        for(int arr : array){
            sum += arr;
        }
        return sum;
    }

    /**
     * 计算数组元素在结果集中出现的次数
     * @param result 结果集
     * @param num 数组元素
     * @param len 数组长度
     * @return
     */
    private static int count(int[] result,int num, int len) {
        int count = 0;
        for (int j=0; j<len; j++){
            if(num == result[j]){
                count++;
            }
        }
        return count;
    }

    /**
     * 获取元素在数组中的位置,如果不存在返回 null
     * @param array 数组
     * @param len 长度
     * @param num 数组元素
     * @return
     */
    private static Integer getIndex(int[] array, int len, int num) {
        for (int i=0; i<len; i++){
            if(num == array[i]){
                return i;
            }
        }
        return null;
    }
}

打印结果如下:

 begin:[0,1]
result:null

 begin:[0,1,2]
result:null

 begin:[0,1,2,3]
 result:[1,2,1,0]

 begin:[0,1,2,3,4]
result:null

 begin:[0,1,2,3,4,5]
result:null

 begin:[0,1,2,3,4,5,6]
 result:[3,2,1,1,0,0,0]

 begin:[0,1,2,3,4,5,6,7]
 result:[4,2,1,0,1,0,0,0]

 begin:[0,1,2,3,4,5,6,7,8]
 result:[5,2,1,0,0,1,0,0,0]

 begin:[0,1,2,3,4,5,6,7,8,9]
 result:[6,2,1,0,0,0,1,0,0,0]

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值