神奇数

【编程题】

【题目描述】 :东东在一本古籍上看到有一种神奇数,如果能够将一个数的数字分成两组,其中一组数字的和等于另一组数字的和,我们就将这个数称为神奇数。例如242就是一个神奇数,我们能够将这个数的数字分成两组,分别是{2,2}以及{4},而且这两组数的和都是4.东东现在需要统计给定区间中有多少个神奇数,即给定区间[l, r],统计这个区间中有多少个神奇数,请你来帮助他。
输入描述
输入包括一行,一行中两个整数l和r ( 1 ≤ l , r ≤ 1 0 9 , 0 ≤ r − l ≤ 1 0 6 ) (1 ≤ l, r ≤ 10^9, 0 ≤ r - l ≤ 10^6) (1l,r109,0rl106),以空格分割
*输出描述
输出一个整数,即区间内的神奇数个数

输入示例
1 50
输出示例
4

解题思路:

首先这道题和Leetcode上的416题Partition Equal Subset Sum的解法是一样的。 这是一道动态规划中的01背包问题。
解题步骤:

    1. 要把数字按位转化成数组。
    1. 每位数字累计求和
    1. 数组中元素和是否能累加成半和。(01背包问题)

C/C++版

#include <iostream>
using namespace std;

bool isMagicArr(int index, int sum, int* nums) 
{
	if (sum == 0)		// 递归结束条件1
		return true;	
	if (sum < 0 || index < 0)		// 递归条件结束2, 累加和超过了或者数组中没有值了
		return false;
	// num[index]是sum中的一部分或者不是sum中的一部分
	return isMagicArr(index - 1, sum - nums[index], nums) || isMagicArr(index - 1, sum, nums);
}

bool checkMagic(int num)
{
	int nums[11];			// 把数字num按位存到nums中
	int index = 0;
	int sum = 0;			// 每位数字求和
	for ( ; num > 0; index++)
	{
		nums[index] = num % 10;		// 获取并保存每位数字 
		sum += nums[index];			// 每位数字累计求和
		num = num / 10;				// 除去个位数字
	}
	// 每位数和是奇数,则肯定不是神奇数
	if (sum % 2 != 0)
		return false;

	return isMagicArr(index, sum / 2, nums);
}

int main()
{
	int l = 0, r = 0;
	while (true)
	{
		cin >> l >> r;
		int count = 0;
		if (l > r)
			break;
		for (int num = l; num <= r; num++)
		{
			if (checkMagic(num))
				count++;
		}
		cout << count << endl;
	}
	system("pause");
    return 0;
}

java版

import java.util.Scanner;

/**
 * Author: snowy
 * 京东2018秋招笔试题2: 神奇数  同leetcode上第416题
 * 【题目描述】 链接:https://www.nowcoder.com/questionTerminal/56d818ae68134c12b26e81f41ecafb9e
 *              东东在一本古籍上看到有一种神奇数,如果能够将一个数的数字分成两组,其中一组数字的和等于另一组数字的和,我们就将这个数称为神奇数。
 *              例如242就是一个神奇数,我们能够将这个数的数字分成两组,分别是{2,2}以及{4},而且这两组数的和都是4.
 *              东东现在需要统计给定区间中有多少个神奇数,即给定区间[l, r],统计这个区间中有多少个神奇数,请你来帮助他。
 *
 *  输入描述:  输入包括一行,一行中两个整数l和r(1 ≤ l, r ≤ 10^9, 0 ≤ r - l ≤ 10^6),以空格分割
 *  输出描述:  输出一个整数,即区间内的神奇数个数
 * */

public class CheckMagic {

    // 不带有数组优化的
    public static boolean checkMagic(int n) {
        int []nums = new int[11];       // 把数字n按位存到nums中
        int index = 0;
        int sum = 0;                    // 每位数字求和

        for (; n > 0; index ++) {
            nums[index] = n % 10;          // 获取并保存每位数字
            sum += nums[index];             // 每位数字累计求和
            n /= 10;                        // 除去个位数字
        }

        if (sum % 2 != 0)
            return false;

        return isMagic(index, sum/2, nums);
    }

    public static boolean isMagic(int index, int sum, int[] nums) {
        if(sum == 0)
            return true;
        if(index < 0 || sum < 0)
            return false;

        return isMagic(index - 1, sum - nums[index], nums) || isMagic(index - 1, sum, nums);
    }

    // 带有滚动数组的优化
    public static boolean checkMagicWithRollarray(int n) {
        int []nums = new int[11];       // 把数字n按位存到nums中
        int index = 0;
        int sum = 0;                    // 每位数字求和

        for (; n > 0; index ++) {
            nums[index] = n % 10;          // 获取并保存每位数字
            sum += nums[index];             // 每位数字累计求和
            n /= 10;                        // 除去个位数字
        }

        if (sum % 2 != 0)
            return false;

        boolean []dp = new boolean[sum / 2 + 1];
        dp[0] = true;

        return isMagicWithRoll(index, sum/2, nums, dp);
    }

    private static boolean isMagicWithRoll(int index, int sum, int[] nums, boolean[] dp) {
        for (int i = 0; i < index; i ++) {		// 遍历nums数组
            for (int s = sum; s >= nums[i]; s --) {	
                if (s - nums[i] == 0)
                    dp[nums[i]] = true;
                else
                    dp[s] = dp[s] || dp[s - nums[i]];
            }
        }
        return dp[sum];
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        System.out.println("Pleace input:");

        while (input.hasNext()) {
            int l = input.nextInt();
            int r = input.nextInt();
            if ( l > r)
                break;
            int count = 0;
            for (int num = l; num <= r; num ++) {
                if(checkMagicWithRollarray(num))
                    count ++;
            }
            System.out.println(count);
            System.out.println("Pleace input:");
        }
    }
}

思考:在这道题目中数字数要按照为进行拆分的,因此1055这个数字就不是神奇数,如果不局限于按照位进行拆分,则该数字能拆分成{10}和{5,5},这样是否也是可行的,对于这种情况下的神奇数有空的时候补上相应的程序。

本文参考: https://www.jianshu.com/p/02bae2d23b4a

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值