数据结构与算法分析--Java语言描述(第二章(1))

2023-11-04

习题2.8

假设需要生成前N个自然数的一个随机置换。例如,{4,1,2,5,2} 和 {3,1,4,2,5} 就是合法的置换,但 {5,4,1,2,1} 却不是,因为数1出现了两次而数 3 缺没有。这个程序常常用于模拟一些算法。我们假设存在一个随机数生成器 randInt(i, j) ,它以相同的概率生成 i 和 j 之间的一个整数。

下面是三个算法:

1.如下填入a[0]到a[N-1]的数组a;为了填入a[i],生成随机数直到它不同于已经生成的a[0],a[1], ... ,a[i-1]时,再将其填入a[i]。
2.同算法1,但是要保存一个附加的数组,称之为Used(用过的)数组。当一个随机ran最初被放入数组a的时候,置Used[ran]=1。这就是说,当用一个随机数填入 a[i] 时,可以用一步来测试是否该随机数已经被使用,而不是像第一个算法那样(可能)进行 i 步测试。

3.填写该数组使得 A[i] = i + 1。然后
for(i = 1; i < N; i++)
 swap(&A[i], &A[randInt(0, i)]);

/**
 * @description: 假设需要生成前N个整数的一个随机置换。例如,{4,3,1,5,2}和{3,1,4,2,5}就是合法的置换,但{5,4,1,2,1}却不是,因为数1出现两次而数3却没有。
 * @author: 
 * @date: 2018/7/24
 */
public class RandomReplace {

    /**
     * 随机数生成器randInt(i,j),它以相同的概率生成i和j之间的一个整数。
     *
     * @param i
     * @param j
     * @return
     */
    private int randInt(int i,int j){
        Random rand = new Random();
        // 生成区间[i,j]的随机数
        return rand.nextInt(j-i + 1) + i;
    }

    /**
     * 方法一:填入从a[0]到a[n-1]的数组a,为了填入a[i],生成随机数直到它不同于已经生成的a[0],a[1],...,a[i-1]时,再将其填入a[i]。
     *
     * 时间复杂度为O(N^2)
     * @param a
     */
    public int[] randFun1(int[] a){
        for(int i = 0; i < a.length; i++){
            a[i] = randInt(1,a.length);
            for(int j = 0; j < i; j++){
                if(a[i] == a[j]){
                    a[i] = randInt(1,a.length);
                    j = -1;
                }
            }
        }
        return a;
    }

    /**
     * 方法二:同方法一,但是要保存一个附加的数组,称为used数组。当一个随机数ran最初被放入数组a的时候,置used[ran] = true。
     * 这就是说,当用一个随机数填入a[i]时,可以用一步来测试是否该随机数已经被使用。
     *
     * 时间复杂度为O(N)
     * @param a
     * @return
     */
    public int[] randFun2(int[] a){
        int[] used = new int[a.length + 1];
        for(int i = 0; i < a.length; i++){
            a[i] = randInt(1,a.length);
            while(used[a[i]] != 0){
                a[i] = randInt(1,a.length);
            }
            used[a[i]] = 1;
        }
        return a;
    }

    /**
     * 方法三:填写该数组使得a[i]=i+1。然后for(i=1; i<n; i++)
     *                                     swapReferences(a[i], a[randInt(0,i)]);
     * @param a
     * @return
     */
    public int[] randFun3(int[] a){
        for(int i = 0; i < a.length; i++){
            a[i] = i + 1;
        }
        //随机交换位置
        for(int i = 1; i < a.length; i++){
            swapReferences(a,i,randInt(0,i));
        }
        return a;
    }

    private void swapReferences(int[] arr,int a,int b) {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }

    /**
     * 打印数组
     *
     * @param arr
     */
    private static void printArr(int[] arr){
        for(int i =0; i < arr.length; i++){
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        RandomReplace rand = new RandomReplace();
        System.out.println(rand.randInt(0,2));
        int[] a = new int[5];
//        rand.randFun1(a);
//        rand.randFun2(a);
        rand.randFun3(a);
        printArr(a);

    }
}

习题2.16

基于下列各式编写另外的gcd算法(其中a>b)

gcd(a,b)=2gcd(a/2,b/2)若a和b均为偶数。
gcd(a,b)=gcd(a/2,b)若a为偶数, b为奇数。
gcd(a,b)=gcd(a,b/2)若a为奇数, b为偶数。
gcd(a,b)=gcd((a+b)/2,(a-b)/2)若a和b均为奇数。

    /**
     * 最大公约数(欧几里得算法)
     * 假设M ≥ N,如果N < M,则循环的第一次迭代将它们互换。
     *
     * @param m
     * @param n
     * @return
     */
    public long gcd(long m,long n){
        while(n != 0){
            long rem = m % n;
            m = n;
            n = rem;
        }
        return m;
    }

   public long gcd2(long m,long n){
        // a和b均为偶数
        if((m&1) == 0 && (n&1) == 0){
            return 2 * gcd(m/2,n/2);
        }
        //a为偶数, b为奇数。
        else if((m&1) == 0 && (n&1) != 0){
            return gcd(m/2,n);
        }
        //a为奇数, b为偶数
        else if((m&1) != 0 && (n&1) == 0){
            return gcd(m,n/2);
        }
        //a和b均为奇数
        else {
            return gcd((m+n)/2,(m-n)/2);
        }
    }

    /**
     * 最小公倍数(两个数乘积除以最大公约数)
     *
     * @param m
     * @param n
     * @return
     */
    public long lcm(long m,long n){
        long gcd = gcd(m, n);
        return m * n / gcd;
    }

习题2.17

给出有效的算法

a.求最小子序列和。

b.求最小的正子序列和。

c.求最大子序列乘积。

1.求最小子序列和。

    /**
     * 最小子序列和
     *
     * @param arr
     * @return
     */
    public static int getMinSeq(int[] arr) {
        int minSum = 0;
        if(arr != null && arr.length > 0){
            minSum = arr[0];
            int thisSum = 0;
            for (int i = 0; i < arr.length; i++) {
                thisSum += arr[i];
                if (thisSum < minSum) {
                    minSum = thisSum;
                } else if (thisSum > 0) {
                    thisSum = 0;
                }
            }
        }
        return minSum;
    }

2.求最小的正子序列和。 

     /**
     * 最小正子序列和:1.连续子序列,2.序列和为正且最小
     * 思路:
     * (1)先求出数组的前缀数组之和,例如:2,-3,-3,7,5=>前缀数组和为2,-1,-4,3,8(它们的索引0 1 2 3 4)
     * (2)对前缀数组进行排序得到:-4,-1,2,3,8
     * (3)则最小值一定是在:-4,1,2,3,8(结果一定在当前项减去前面一项,同时满足索引大于前一项的索引)
     *
     * @param arr
     * @return
     */
    public static int getMinPositiveSeq(int[] arr) {
        int minPosSum = 0;
        int len = arr.length;
        int[] newArr = new int[len];

        for(int i = 0; i < len; i++){
            minPosSum += arr[i];
            newArr[i] = minPosSum;
        }
        // 快速排序
        quickSort(newArr,0,len - 1);
        int min = newArr[0] >= 0 ? newArr[0] : newArr[len - 1];
        for(int i = 1; i < len; i++){
            if(newArr[i] > newArr[i - 1]){
                int temp = newArr[i] - newArr[i - 1];
                if(temp < min){
                    min = temp;
                }
            }
        }
        return min;
    }

    /**
     * 快速排序
     * 1.从数组中选择一个数作为基准数。
     * 2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边
     * 3.再对左右区间重复第2步,直到各区间只有一个数
     *
     * @param arr
     * @param low
     * @param high
     */
    private static void quickSort(int[] arr,int low,int high){
        if(low < high){
            int index = partition(arr,low,high);
            quickSort(arr,low,index - 1);
            quickSort(arr,index + 1,high);
        }
    }


    /**
     * 进行第一轮排序获取分割点
     *
     * @param arr
     * @param low
     * @param high
     * @return
     */
    private static int partition(int[] arr,int low,int high){
        int pivot = arr[high];
        int small = low - 1;

        for(int i = low; i < high; i++){
            //将比pivot值小的数放到左边
            if(arr[i] <= pivot){
                small++;
                swap(arr,i,small);
            }
        }
        swap(arr,high,small + 1);
        return small + 1;
    }

3. 求最大子序列乘积。

     /**
     * 最大子序列乘积
     * 方法一:动态规划,每一步只需要记住其前一步的整数最大值和负数的最小值。
     * @param arr
     * @return
     */
    public static int getMaxSeqMulti(int[] arr){
        if(arr == null || arr.length < 0){
            return 0;
        }
        int maxMulti = arr[0];
        int posMax = arr[0];
        int negMin = arr[0];
        for(int i = 1; i < arr.length; i++){
            int tempPosMax = posMax;
            int tempNegMax = negMin;
            posMax = Math.max(arr[i],Math.max(tempPosMax * arr[i],tempNegMax * arr[i]));
            negMin = Math.min(arr[i],Math.min(tempPosMax * arr[i],tempNegMax * arr[i]));
            if(Math.max(posMax,negMin) > maxMulti){
                maxMulti = Math.max(posMax,negMin);
            }
        }
        return maxMulti;
    }

    /**
     * 最大子序列乘积
     * 方法二:
     * @param arr
     * @return
     */
    public static int getMaxSeqMulti2(int[] arr){
        int max = Integer.MIN_VALUE;
        for(int i = 0; i < arr.length; i++){
            int temp = arr[i];
            for(int j = i + 1; j < arr.length; j++){
                max = Math.max(max,temp);
                temp *= arr[j];
            }
            max = Math.max(max,temp);
        }
        return max;
    }

习题2.20

编写一个程序来确定正整数N是否是素数。

思路:

如果一个数不是素数,那它除了1和本身一定还有其他的约数。我们假设这个数是num,num=m*n 一定可以分解为两个整数相乘。
设一个命题 ,num可以分解为两个数相乘并且这两个数都大于num的平方根
m>sqrt(num)
n>sqrt(num)
根据数学知识可以知道m*n>num 这与命题相反,所以命题是假的。

所以合数一定至少有一个不大于sqrt(num)约数,只要找到这个数就可以了。

    /**
     * 方法二:判断是否是素数,运行时间为O(√N)
     *
     * @param N
     * @return
     */
    public boolean isPrime(int N){
        if(N == 1){
            return false;
        }
        for(int i = 2; i <= Math.sqrt(N); i++){
            if(N % i == 0){
                return false;
            }
        }
        return true;
    }

问题拓展:获取2~N之间的所有素数。 

    /**
     * 方法一:获取2~N之间的所有素数
     * 用ArrayList保存
     *
     * @param N
     */
    public void getPrime1(int N){
        List<Integer> list = new ArrayList<>();
        for(int i = 2; i <= N; i++){
            if(isPrime(i)){
                list.add(i);
            }
        }
        for(Integer prime : list){
            System.out.print(prime + " ");
        }
    }

    /**
     * 方法二:双层for循环得出素数
     *
     * @param N
     */
    public void getPrime2(int N){
        for(int i = 2; i <= N; i++){
            int j;
            //测试2至i的数字是否能被i整除,如不能就自加
            for(j = 2; j <= i; j++){
                if(i % j == 0){
                    break;
                }
            }
            //当有被整除的数字时,判断它是不是自身,若是,则说明是素数
            if(j == i)
                System.out.print(j + " ");
        }
    }

厄拉多塞筛选法
筛选法,是指从小到大筛去一个已知素数的所有倍数。
例如:根据2,我们筛选去4,6,8jiang,....,98,100等数;然后根据3,我们可以筛选9,15,...99等数(注意此时6、12等数早就被筛去了);
由于4被筛去了,下一个用于筛选的素数是5,以此类推,最后剩余的就是100以内的素数。 

public void getPrime3(int N){
        //默认isComposite为false
        boolean[] isComposite = new boolean[N + 1];
        for(int m = 2; m <= Math.sqrt(N); m++){
            //筛选 m 的倍数,将isComposite置为true
            if(!isComposite[m]){
                for(int k = m * m; k <= N; k += m){
                    isComposite[k] = true;
                }
            }
        }
        //剩下所有isComposite为false的数即为素数
        for(int m = 2; m <= N; m++){
            if(!isComposite[m]){
                System.out.print(m + " ");
            }
        }
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据结构与算法分析--Java语言描述(第二章(1)) 的相关文章

  • 动态规划 - 钢条切割问题

    已知钢条切割的不同长度对应的不同价格如下所示 长度i 1 2 3 4 5 6 7 8 9 10 价格pi 1 5 8 9 10 17 17 20 24 30 求输入长度 输出最佳的收益 详细理论知识见 算法导论第十五章 P359 书中给出三
  • maven 通过profiles管理不同环境的依赖和插件

    Profile能让你为一个特殊的环境自定义一个特殊的构建 profile使得不同环境间构建的可移植性成为可能 Maven中的profile是一组可选的配置 可以用来设置或者覆盖配置默认值 有了profile 你就可以为不同的环境定制构建 p
  • 基于SSM的客户管理系统的设计与实现

    项目描述 该项目采用了SSM作为后端开发框架 系统中分为管理员 客户经理 销售主管 和高管四种用户角色 在项目中实现了营销管理 服务管理 统计报表 基础数据管理以及 系统管理等功能模块 下载地址 http www hrxxkj com we
  • 【C语言】辗转相除法+更相减损术+秦九韶算法

    一 辗转相除法 1 简介 辗转相除法又叫欧几里得算法 假如需要求 1997 和 615 两个正整数的最大公约数 用欧几里得算法 是这样进行的 1997 615 3 余 152 615 152 4 余7 152 7 21 余5 7 5 1 余
  • JackSon的用法详解

    JackSon的用法详解 JackSon的用法详解
  • chisel测试指令

    第一步 chisel 转换成firrtl类型 sbt test only 包名 测试类名 第二步 firrtl转换成verilog 指向verilator TESTER BACKENDS verilator sbt test only 包名
  • VMware vSphere基础命令大全

    VMware vSphere是VMware公司的虚拟化平台 包括ESXi hypervisor和vCenter Server两大组件 作为vSphere平台的管理员 掌握常用的vSphere管理命令是必要的 这些命令主要在vSphere C
  • proto文件支持继承吗_关于ES6中继承的问题 B继承A B.__proto__ = A?

    B proto proto 确实是 Function prototype 但首先它的原型是 A 其原型的原型才是函数原型 因为定义在 A 上的静态方法 B 也要继承 更新 每一个对象都有原型 但是对象的原型并不一定是对象的构造函数的 pro
  • runoob.com菜鸟教程-redis命令查询

    http www runoob com redis redis transactions html
  • asn1c编解码时 Assertion ‘lb <= ub‘ failed问题

    近期在使用asn编解码时提示 per support c 238 per long range rebase Assertion lb lt ub failed 经过查找资料和分析 找到解决办法 如下 修改INTEGER c 文件
  • 瑞芯微Rockchips RK3368对比晶晨Amlogic S905

    回首过去的2015上半年 国内网络机顶盒64位处理器一直被瑞芯微RK3368垄断着 到了2015年下半年 随着天猫魔盒M13和小米盒子3等电视盒子的曝光 预售与上市 瑞芯微RK3368的在电视盒子中64位处理器的垄断地位也被打破 因为天猫魔
  • 如何在vue项目中引入字体图标

    第一步 进入阿里图标库 选择自己需要的图标 第二步 选择之后不要点击下载 点击加入购物车 第三步 点击右上角的购物车 然后点击添加至项目可以新建项目名称 第四步 然后点击红字复制代码 注 画红框的是引用字体图标时的名字 点击画框的地方 在新
  • Qt设计师的简单使用(ui设计界面的简单使用)

    文章目录 一 界面的基本介绍 二 添加控件 2 1 添加控件 2 2 设置控件属性 三 布局器的使用 3 1 布局器介绍 3 2 简单布局 3 3 复杂布局 3 4 带分裂器的布局 四 拓展 4 1 添加模块窗口 4 2 转到槽的使用 4
  • M3U8视频AES解密播放

    在网站上看到一些有意思的视频想要下载下来的时候 发现没有找不到mp4格式的地址 因为该网站视频播放是HLS HTTP Live Streaming 技术 HLS是Apple公司研发的流媒体传输技术 包括一个m3u8的索引文件 多个ts分片文
  • MySql锁机制(全网最全、最详细、最清晰)

    1 MySql锁机制 锁机制的作用 解决因为资源共享 而造成的并发问题 没有锁机制时 例如一号用户和二号用户都要去买同一件商品 假如这件商品是一件衣服 一号用户手速稍微快了一些 于是就先买到了这件衣服 但是因为没有 锁机制 于是就造成了二号
  • 【笔试强训选择题】Day28.习题(错题)解析

    作者简介 大家好 我是未央 博客首页 未央 303 系列专栏 笔试强训选择题 每日一句 人的一生 可以有所作为的时机只有一次 那就是现在 文章目录 前言 一 Day28习题 错题 解析 总结 前言 一 Day19习题 错题 解析 1 解析

随机推荐

  • ES高可用及集群管理

    ES高可用及集群管理 Elasticsearch 是一个分布式 高扩展 高实时 RESTful 风格的搜索与数据分析引擎 服务可用性 允许有节点停止服务 数据可用性 部分节点丢失 不会丢失数据 水平扩展 集群容错 一 分片 1 什么是分片及
  • Unity Blend Tree动画的混合,认识Blend Tree

    我们在Animator Controller中除了可以创建一个State外还可以创建一个Blend Tree 如下 那么我们看下新创建的Blend Tree和State有什么区别 唯一的区别就是Montion指向的类型变成了Blend Tr
  • 启动测试(建立索引库,映射,用分页结果集的方法把当前的页面的商品数据拿到后,再用do,while方法把当前商品页面转换给goods列表,再把结果导入索引库)

    我们要去实现对上一次内容的测试 上一次内容大概就是讲了怎么样去完成Goods查询页面的编写 下面的测试当中需要把上次做完的东西导入索引库当中对索引库进行增删改查 然而就会用到下面的方法 一个是Template方法 导入索引库 一个是Repo
  • python调用摄像头

    import cv2 模块称作cv2 python需要用到opencv python模块 可在命令行模式输入 pip install opencv python i https pypi douban com simple capture
  • AI建模

    三维重建是将客观世界中的物体在虚拟空间表达出来 在大众视野中 物品三维重建最直观的应用当属虚拟仿真和VR AR导航 其实在学科专业领域 三维重建已经更早地应用在高精地图 测绘系统 城市规划等领域 科技发展的终极方向应当是普适性 结合现代信息
  • Git的下载及使用

    一 Git的下载 1 下载Git 打开Git官网进行下载Git git scm com 直接点击Download for Windows进入Git版本页面 在此页面根据自己电脑的操作系统选择相应的Git版本 2 安装程序 下载完成之后双击g
  • 炒冷饭,springboot自定义logo详解

    初学springboot的朋友 是不是经常能看到项目启动时日志打印的springboot图标logo 有没有人想让他长成自己的样子 现在我就告诉你 如果不想显示logo 你可以在配置文件中增加如下配置 spring main banner
  • 64位操作系统不能安装64位虚拟机的解决办法

    很多人都遇到过这样的情况把 就是自己的电脑CPU明明是64的 为什么安装64的虚拟机却不能安装 安装时出现如下错误 但是在真实机上安装却没有问题 这是为什么呢 这是因为你电脑的硬件虚拟化没有开启 据说host系统是64位的 guest系统才
  • 1.错误处理org.apache.jasper.JasperException: The absolute uri: http://java.sun.com/jsp/jstl/core。是什么原因造成

    解决方法 tomcat 8 5 启用项目时提示 无法在web xml或使用此应用程序部署的jar文件中解析绝对uri http java sun com jsp jstl core 项目需要扫描Tld文件 修改一下tomcat 配置conf
  • retrofit应用详解与源码解析--奇技淫巧

    本文出自门心叼龙的博客 属于原创类容 未经允许 不得转载 本专栏的同步视频教程已经发布到CSDN学院 https edu csdn net course detail 30408 文章目录 请求超时设置 日志拦截器的设置 网络的缓存设置 自
  • linux shell中\w \s \d \b ^ $等常用匹配用法

    正则表达式 w s d b 用法 匹配除换行符以外的任意字符 w 匹配字母或数字或下划线 s 匹配任意的空白符 d 匹配数字 等价于 0 9 D 匹配非数字字符 b 匹配单词的开始或结束 匹配字符串的开始 匹配字符串的结束 其中 A Z 表
  • running beyond physical memory limits. Current usage: 2.0 GB of 2 GB physical memory used; 2.6 GB of

    昨天使用hadoop跑五一的数据 发现报错 Container pid 47660 containerID container 1453101066555 4130018 01 000067 is running beyond physic
  • starUML教程-用例图/类图

    用例图 也称为用户模型图 是从软件需求分析到最终实现的第一步 它是从客户的角度来描述系统功能 它包含3个基本组件 1 参与者 与系统打交道的人或使用该系统的人 2 用例 表示该系统的某项完整功能 3 关系 定义用例之间的关系 泛化关系 扩展
  • 蓝桥杯每日一题(12):猜年龄(小明)(python)

    Topic 来道简单的 小明带两个妹妹参加元宵灯会 别人问她们多大了 她们调皮地说 我们俩的年龄之积是年龄之和的6倍 小明又补充说 她们可不是双胞胎 年龄差肯定也不超过8岁啊 请你写出 小明的较小的妹妹的年龄 Solution 填空题以快为
  • 【web安全】——命令执行漏洞(RCE)详解

    作者名 Demo不是emo 主页面链接 主页传送门创作初心 舞台再大 你不上台 永远是观众 没人会关心你努不努力 摔的痛不痛 他们只会看你最后站在什么位置 然后羡慕或鄙夷座右铭 不要让时代的悲哀成为你的悲哀专研方向 网络安全 数据结构 每日
  • 华为OD机试 - 找出两个整数数组中同时出现的整数(Java)

    题目描述 现有两个整数数组 需要你找出两个数组中同时出现的整数 并按照如下要求输出 有同时出现的整数时 先按照同时出现次数 整数在两个数组中都出现并目出现次数较少的那个 进行归类 然后按照出现次数从小到大依次按行输出 没有同时出现的整数时
  • 区块链分布式存储

    想知道更多区块链技术知识 请百度 链客区块链技术问答社区 链客 有问必答 BAT垄断了互联网创业道路 DAPP成为创投界新趋势 区块链革命引领市场变天 区块链 创业当红 互联网 创业成为经典 Dapp 区块链 应用 将会如何改变我们的互联网
  • Nacos配置中心一直连接本地问题&解决

    最近使用写了一个微服务的demo 使用nacos做配置中心 项目启动我的nacos一直去连接本地 配置文件中也指定了nacos的地址 后来 也是查阅资料才得知 bootstrap yml bootstrap properties 用来在程序
  • Vue解决CDN引入的echarts,通过ajax异步请求的数据不能被正确渲染到视图层的问题

    在参加计算机设计大赛做作品的时候遇到的一个困难 花了挺长时间才解决 在这里做个记录 一 这里先介绍如何CDN引入ECharts 在需要用到ECharts的界面加入 即可 或者先下载好这个文件 src改为这个文件的相对路径 二 以南丁格尔玫瑰
  • 数据结构与算法分析--Java语言描述(第二章(1))

    习题2 8 假设需要生成前N个自然数的一个随机置换 例如 4 1 2 5 2 和 3 1 4 2 5 就是合法的置换 但 5 4 1 2 1 却不是 因为数1出现了两次而数 3 缺没有 这个程序常常用于模拟一些算法 我们假设存在一个随机数生