java:将一个正整数拆分为n个非负数之和

本文介绍了一种使用Java实现的算法,该算法能够将一个正整数拆分为指定数量的非负数之和,并提供了具体的实现代码及运行示例。

java:将一个正整数拆分为n个非负数之和

1 前言

将一个正整数拆分为n个两数之差,即可获取到结果,公式如下:

x = (xn - x(n-1)) + (x(n-1) - x(n-2)) +... + (x3 - x2) + (x2 - x1) + (x1 - 0)

其中x = xn, 上述括号中每个数, 即为拆分的n个非负数

2 使用

java实现逻辑:

package com.xiaoxu.test.other;

import com.google.common.collect.Lists;

import java.util.Comparator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author xiaoxu
 * @date 2023-01-29
 * java_demo:com.xiaoxu.test.other.SplitDemo
 */
public class SplitDemo {

    /**
     * @param value 需要拆分的数值
     * @param splitCount 总共拆分为splitCount个非负数,拆分的全部非负数之和,等于需要拆分的数值value(拆分数中可能含有0)
     */
    public static List<Long> demo(long value, int splitCount){
        if(value <= 0 || splitCount <= 0){
            throw new RuntimeException("should not be 0");
        }

        List<Long> splitArr = Lists.newArrayList();

        if(splitCount == 1){
            splitArr.add(value);
            return splitArr;
        }

        int exeCount = 0;

        Random rand = new Random();
        List<Double> randRange;
        int var1;

        /*
        * 规避随机数中含相同数的情况,实际概率极小
        * */
        do{
            var1 = splitCount - 1;
            randRange = Lists.newArrayList();

            do{
                randRange.add(rand.nextDouble());
            }while(--var1 > 0);

            exeCount ++;

            if(exeCount > 3){
                throw new RuntimeException("repeat execute fail!!");
            }

        }while(randRange.stream().distinct().count() != randRange.size());

        /*
        * 顺序排序,由小到大(避免中间变量相减后出现为负数的情况)
        * */
        randRange.sort(new Comparator<Double>() {
            @Override
            public int compare(Double o1, Double o2) {
                return o1 < o2 ? -1 : 1;
            }
        });

        AtomicInteger atmInt = new AtomicInteger();

        long var2 = 0;

        do{

            if(atmInt.get() == splitCount - 1){
                splitArr.add(value - var2);
                break;
            }

            long var3 = (long)(randRange.get(atmInt.getAndIncrement()) * value);
            long var4 = var3 - var2;
            splitArr.add(var4);
            var2 = var3;

        }while(atmInt.get() < splitCount);

        return splitArr;
    }

    public static void main(String[] args) {
        List<Long> demoArr = demo(133, 6);
//        List<Long> demoArr = demo(5, 6);
        System.out.println("arr:" + demoArr);
        System.out.println("total:" + demoArr.stream().reduce(Long::sum)
                .orElseThrow(() -> new RuntimeException("wrong")));
    }

}

执行效果如下(拆分的数中,可能存在为0的场景):

arr:[21, 22, 23, 4, 51, 12]
total:133

再次执行如下场景:

List<Long> demoArr = demo(5, 6);
System.out.println("arr:" + demoArr);
System.out.println("total:" + demoArr.stream().reduce(Long::sum)
        .orElseThrow(() -> new RuntimeException("wrong")));

效果如下:

arr:[0, 1, 0, 1, 1, 2]
total:5
<think>嗯,用户的问题是关于如何在Java中把一个字的偶位变为0,奇位变为1。首先,我需要理解用户的具体需求。这里的“位”可能指的是二进制位,也可能是十进制中的各个字位。过根据常见的编程问题,通常这样的问题指的是二进制位操作,但用户提供的引用内容中提到了奇偶的判断,使用的是取余运算符,所以可能需要先确认用户的需求。 查看用户提供的引用内容,引用[1]和[2]讨论了使用三目运算符和取余运算判断字的奇偶性,引用[3]是一个C语言的例子,处理的是十进制各位的奇偶性,生新的字。用户的问题可能类似于引用[3],但要在Java中实现,将十进制字中的偶位变为0,奇位变为1。这里的“位”可能指的是十进制中的各个字位,比如个位、十位、百位等,而是二进制位。 接下来,我需要考虑如何遍历一个字的每一位,判断该位是奇还是偶,然后进行相应的替换。例如,字1234,各位分别是1(奇)、2(偶)、3(奇)、4(偶),处理后应该变为1变1,2变0,3变1,4变0,所以结果可能是1010?或者用户可能希望每个位单独处理,比如每一位如果是奇就替换为1,偶替换为0,然后组新的字。 根据引用[3]的代码,它处理的是十进制每一位,奇位(比如字位上的值是奇)替换为1,偶位替换为0,然后组合一个新的字。例如,输入1234,得到1010。用户的问题应该与此类似,但需要确认是十进制的每一位还是二进制位。 因此,解决方案的大致步骤应该是: 1. 遍历输入字的每一位十进制字。 2. 判断该位是奇还是偶。 3. 如果是奇,将该位变为1;如果是偶,变为0。 4. 将这些0和1按原来的位顺序组合新的字。 在Java中,可以通过循环取余和除法来逐位处理。例如,每次取n%10得到最后一位,判断奇偶,然后替换为1或0,再将这个结果乘以相应的10的幂次累加到结果中。同时,需要记录当前处理到第几位,以确定乘以10的几次方。 需要注意的是,原字可能包含0,这时候0会被替换为0。另外,如果原字某位是0,处理后的该位还是0。例如,输入字为304,各位是3(奇→1)、0(偶→0)、4(偶→0),结果应该是100。 另外,需要考虑负数的情况。如果输入为负数,处理方式是否与正相同?比如,-1234,处理后的符号如何处理?可能需要在处理前取绝对值,处理完后再恢复符号。 现在,需要编写Java代码实现这个过程。例如: 1. 读取输入字,可能为负数,所以先取绝对值处理。 2. 初始化结果sum为0,位置i为0。 3. 循环处理每一位: a. 取当前位bit = n % 10。 b. 判断bit是否为偶,如果是,替换为0;否则替换为1。 c. 将替换后的值乘以10^i,加到sum上。 d. n = n / 10,i++。 4. 处理完所有位后,恢复原来的符号(如果输入为负数,则sum乘以-1)。 但需要注意,当原字的某位是0时,替换为0,例如输入为0,则结果是0。输入为10,处理后的结果是00,即0。 测试几个例子: 输入1234 → 1010 输入304 →100 输入0 →0 输入-567 →-101 接下来,编写Java代码,可能用到循环、取余、幂运算等。对于幂运算,可以使用Math.pow,但返回的是double,需要转换为int。例如,在引用[3]的C代码中使用了pow函,但Java中的Math.pow同样需要注意类型转换。 需要注意的是,如果输入的字是0,则循环会执行,所以需要单独处理这种情况。 另外,对于用户提到的“偶位”和“奇位”,需要确认是否是按位置(比如从右往左,第一位是个位,是奇位还是偶位),但根据用户的问题描述,可能指的是字本身的奇偶性,而是位置。例如,字的某一位是偶还是奇,无论该位处于哪个位置。 现在,编写具体的代码步骤: 1. 获取输入字,处理负数情况。 2. 初始化sum=0,i=0。 3. 处理输入为0的情况,直接返回0。 4. 循环处理每一位: while(n != 0) { int bit = n % 10; int newBit = (bit % 2 == 0) ? 0 : 1; sum += newBit * Math.pow(10, i); i++; n = n / 10; } 5. 恢复符号。 但是,Math.pow返回的是double,乘以10^i可能会导致精度问题,例如当i较大时,可能会有误差。因此,可能需要手动计算10的幂次,比如使用一个变量power,初始为1,每次循环乘以10,这样更可靠。 改进后的循环: int sum = 0; int power = 1; n = Math.abs(number); // 处理负数 while(n != 0) { int bit = n % 10; int newBit = (bit % 2 == 0) ? 0 : 1; sum += newBit * power; power *= 10; n = n / 10; } if (number < 0) { sum *= -1; } 这样处理会更准确,避免了使用Math.pow的精度问题。 例如,输入1234: n=1234,循环: bit=4 →0 →sum +=0*1=0 →power=10 bit=3 →1 →sum +=1*10=10 →power=100 bit=2 →0 →sum +=0*100=10 →power=1000 bit=1 →1 →sum +=1*1000=1010 →结束。正确。 输入304: bit=4 →0 →sum=0 →power=10 bit=0 →0 →sum=0 →power=100 bit=3 →1 →sum=100 →power=1000 →结束,得到100. 输入0的情况需要特殊处理,因为循环会执行,sum保持0,正确。 负数的情况,例如输入-567: 绝对值567的处理结果得到101,然后乘以-1,得到-101,正确。 现在,将这段逻辑转化为Java代码。需要读取用户输入,处理可能的异常(例如输入整数),但根据用户提供的引用[1],使用Scanner类获取输入。 完整代码示例: import java.util.Scanner; public class DigitConverter { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("请输入一个整数:"); int number = scanner.nextInt(); int converted = convertDigits(number); System.out.println("转换后的字为:" + converted); } public static int convertDigits(int number) { if (number == 0) { return 0; } int sum = 0; int power = 1; int n = Math.abs(number); while (n != 0) { int bit = n % 10; int newBit = (bit % 2 == 0) ? 0 : 1; sum += newBit * power; power *= 10; n = n / 10; } return number < 0 ? -sum : sum; } } 这个代码应该可以正确处理正负数,以及0的情况。需要注意的是,如果输入的常大,可能会导致int溢出,可以考虑使用long类型来处理更大的。 用户的问题中提到的“偶位变为0,奇位变为1”中的“位”如果是指十进制的各个字位,那么上述代码是正确的。如果用户指的是二进制位,则需要同的处理方式,但根据引用中的例子,应该是十进制位。 因此,最终的实现方法是逐位处理十进制字,判断每一位的奇偶性,并用0或1替换,然后组合新的字。</think>在Java中,将字的十进制偶位变为0、奇位变为1的实现方法可以分为以下步骤: ### 实现步骤 1. **逐位提取字**:通过取模运算$n \% 10$获取最后一位字 2. **奇偶判断**:用条件运算符判断奇偶性,奇替换为1,偶替换为0 3. **重构字**:通过幂次计算将替换后的值累加到结果中 4. **符号处理**:保留原始字的符号 ```java import java.util.Scanner; public class DigitConverter { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("请输入一个整数:"); int number = scanner.nextInt(); int result = convertDigits(number); System.out.println("转换结果:" + result); } public static int convertDigits(int number) { if (number == 0) return 0; // 单独处理0 int sum = 0; int power = 1; int n = Math.abs(number); // 处理负数 while (n > 0) { int bit = n % 10; int newBit = (bit % 2 == 0) ? 0 : 1; // 条件判断 sum += newBit * power; // 按位累加 power *= 10; n /= 10; } return (number < 0) ? -sum : sum; // 恢复符号 } } ``` ### 代码解析 1. **输入处理**:通过`Scanner`读取用户输入,支持正负数 2. **逐位处理**: - `bit = n % 10`提取当前最低位 - `newBit = (bit % 2 == 0) ? 0 : 1`实现奇偶替换[^1] 3. **重构逻辑**: - `power`变量表示当前位的权重($10^i$) - `sum += newBit * power`将替换后的值按位累加 4. **符号恢复**:通过三元运算符保留原始符号 ### 示例 输入:`1234` → 转换过程: 1. 4→0,3→1,2→0,1→1 2. 按位重组:$0*1 + 1*10 + 0*100 + 1*1000 = 1010$ 输出:`1010`
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值