数据结构与算法-分裂问题,将数字分成0或1,求l到r之间有多少个1.

// 分裂问题

一个数n,可以分裂成一个数组[n/2, n%2, n/2], 这个数组中哪个数不是1或者0,就继续分裂下去。

比如 n = 5,一开始分裂成[2, 1, 2], [2, 1, 2]这个数组中不是1或者0的数,会继续分裂下去,比如两个2就继续分裂 [2, 1, 2] -> [1, 0, 1, 1, 1, 0, 1],那么我们说,5最后分裂成[1, 0, 1, 1, 1, 0, 1]。每一个数都可以这么分裂,在最终分裂的数组中,假设下标从1开始给定三个数n、l、r,返回n的最终分裂数组里[l,r]范围上有几个1。 n <= 2 ^ 50,n是long类型, r - l <= 50000,l和r是int类型。

bash 复制代码
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Code_SplitZeroOne {

    // n = 100
    // n = 100, 最终裂变的数组,长度多少?
    // n = 50, 最终裂变的数组,长度多少?
    // n = 25, 最终裂变的数组,长度多少?
    // ..
    // n = 1 ,.最终裂变的数组,长度多少?
    // 请都填写到lenMap中去!
    public static long len(long n, HashMap<Long, Long> lenMap) {
        if(n == 0 || n == 1){
            lenMap.put(n,1L);
            return 1;
        }

        long half = len(n/2,lenMap);
        long all = (half << 1) + 1;
        lenMap.put(n, all);
        return all;
    }

    // n = 100
    // n = 100, 最终裂变的数组中,一共有几个1
    // n = 50, 最终裂变的数组,一共有几个1
    // n = 25, 最终裂变的数组,一共有几个1
    // ..
    // n = 1 ,.最终裂变的数组,一共有几个1
    // 请都填写到onesMap中去!
    public static long ones2(long num, HashMap<Long, Long> onesMap) {
        if (num == 1 || num == 0) {
            onesMap.put(num, num);
            return num;
        }
        // n > 1
        long half = ones2(num / 2, onesMap);
        long mid = num % 2 == 1 ? 1 : 0;
        long all = half * 2 + mid;
        onesMap.put(num, all);
        return all;
    }

    public static long ones(long n, HashMap<Long, Long> onesMap) {
        if(n == 0 || n == 1){
            onesMap.put(n,n);
            return n;
        }

        int mid = (n % 2) == 1 ? 1 : 0;
        long half = ones(n/2,onesMap);
        long all = (half << 1) + mid;
        onesMap.put(n, all);
        return all;
    }

    public static long nums3(long n, long l, long r) {
        //HashMap<Long, Long> allMap = new HashMap<>();

        HashMap<Long, Long> lenMap = new HashMap<>();
        HashMap<Long, Long> oneMap = new HashMap<>();
        long len = len(n,lenMap);
        long ones = ones(n,oneMap);

        return dp2(n,l,r,lenMap,oneMap);
    }

    public static long dp2(long n, long l, long r, HashMap<Long,Long> lenMap, HashMap<Long,Long> onesMap){
        long allLen = lenMap.get(n);
        if(l <= 1 && allLen <= r){
            return onesMap.get(n);
        }

        long all = 0;
        int mid = (n%2 == 1) ? 1 : 0;
        long halfLen = (allLen-1)/2;
        if(l < halfLen+1){
            all += dp2(n/2,l,Math.min(r,halfLen),lenMap,onesMap);
        }

        if(r > halfLen+1){
            all += dp2(n/2,Math.max(l-halfLen-1,1),r-halfLen-1,lenMap,onesMap);
        }

        all += ((l > halfLen + 1 || r < halfLen + 1) ? 0 : mid);
        return all;
    }

    // 为了测试
    // 彻底生成n的最终分裂数组返回
    public static ArrayList<Integer> test(long n) {
        ArrayList<Integer> arr = new ArrayList<>();
        process(n, arr);
        return arr;
    }

    public static void process(long n, ArrayList<Integer> arr) {
        if (n == 1 || n == 0) {
            arr.add((int) n);
        } else {
            process(n / 2, arr);
            arr.add((int) (n % 2));
            process(n / 2, arr);
        }
    }

    public static long nums1(long n, long l, long r) {
        if (n == 1 || n == 0) {
            return n == 1 ? 1 : 0;
        }
        long half = size(n / 2);
        long left = l > half ? 0 : nums1(n / 2, l, Math.min(half, r));
        long mid = (l > half + 1 || r < half + 1) ? 0 : (n & 1);
        long right = r > half + 1 ? nums1(n / 2, Math.max(l - half - 1, 1), r - half - 1) : 0;
        return left + mid + right;
    }

    public static long size(long n) {
        if (n == 1 || n == 0) {
            return 1;
        } else {
            long half = size(n / 2);
            return (half << 1) + 1;
        }
    }

    public static void main(String[] args) {
        long num = 671;
        ArrayList<Integer> ans = test(num);
        int testTime = 10000;
        System.out.println("功能测试开始");
        for (int i = 0; i < testTime; i++) {
            int a = (int) (Math.random() * ans.size()) + 1;
            int b = (int) (Math.random() * ans.size()) + 1;
            int l = Math.min(a, b);
            int r = Math.max(a, b);
            int ans1 = 0;
            for (int j = l - 1; j < r; j++) {
                if (ans.get(j) == 1) {
                    ans1++;
                }
            }
            long ans2 = nums1(num, l, r);
            long ans3 = nums3(num, l, r);
            if (ans1 != ans2 || ans1 != ans3) {
                System.out.println("出错了!");
            }
        }
        System.out.println("功能测试结束");
        System.out.println("==============");

        System.out.println("性能测试开始");
        num = (2L << 50) + 22517998136L;
        long l = 30000L;
        long r = 800000200L;
        long start;
        long end;
        start = System.currentTimeMillis();
        System.out.println("nums1结果 : " + nums1(num, l, r));
        end = System.currentTimeMillis();
        System.out.println("nums1花费时间(毫秒) : " + (end - start));

        start = System.currentTimeMillis();
        System.out.println("nums3结果 : " + nums3(num, l, r));
        end = System.currentTimeMillis();
        System.out.println("nums3花费时间(毫秒) : " + (end - start));
        System.out.println("性能测试结束");
        System.out.println("==============");

        System.out.println("单独展示nums2方法强悍程度测试开始");
        num = (2L << 55) + 22517998136L;
        l = 30000L;
        r = 6431000002000L;
        start = System.currentTimeMillis();
        System.out.println("nums2结果 : " + nums3(num, l, r)); // -1429513860
        end = System.currentTimeMillis();
        System.out.println("nums2花费时间(毫秒) : " + (end - start));
        System.out.println("单独展示nums2方法强悍程度测试结束");
    }

}
相关推荐
sanshizhang2 小时前
设计模式-责任链模式
java·设计模式·责任链模式
有时间要学习2 小时前
面试150——第六周
算法·面试·深度优先
hetao17338372 小时前
2026-03-04~03-06 hetao1733837 的刷题记录
c++·算法
*.✧屠苏隐遥(ノ◕ヮ◕)ノ*.✧2 小时前
Day01 Junit 单元测试 & 反射
java·后端·junit·单元测试
逆境不可逃2 小时前
【从零入门23种设计模式16】行为型之迭代器模式
java·开发语言·数据结构·算法·设计模式·职场和发展·迭代器模式
JTCC2 小时前
Java 设计模式西游篇 - 第七回:责任链模式过难关 通关文牒层层批
java·设计模式·责任链模式
xiaoye-duck2 小时前
《算法题讲解指南:优选算法-分治-归并》--47.归并排序,48.数组中的逆序对
c++·算法
Darkwanderor2 小时前
图论——最短路问题
c++·算法·图论·最短路
Java练习两年半2 小时前
互联网大厂 Java 求职面试:探讨微服务与云原生
java·微服务·云原生·面试·技术栈