实现大数相乘、实现找到最近两个点的距离

算法大作业


  • 题目1 实现大数相乘
  • 题目要求:
    编程语言内置的数据类型都是有长度限制的,最长的long类型的长度是2^63-1,如果两个数的乘积超过了这个长度,那么就会出现错误,那么如何实现两个长度为20位二进制数字的乘积。
  • 算法思路
  1. 暴力相乘法:
    这个方法的思路主要是使用两个循环模拟手动运算的过程,超出长度的数字用字符串表示,计算的过程中,需要注意在计算过程中的数字的位数调整。时间复杂度为O(n^2)。
  2. 分治法
    分治法的主要思路是将问题分成可直接求解的子问题,针对这个问题可求解的子问题就是两个个位数相乘,可以直接得到结果。分治法在递归的过程中停止条件是两个数字都为个位数。另外,本题目还会用到两个数字乘积的一个性质:ABCD = AC10^n + (BC + A * D)* 10^(n/2) + B*D,这个性质对求解题目非常的重要,主要是在对子问题进行合并的时候,需要确定子问题得到的解的位数。分治法的时间复杂度比较复杂,但是会比暴力相乘法要好一点。

1、暴力相乘法
  • 代码
import com.sun.xml.internal.fastinfoset.util.CharArray;

public class BigNumber_Brute_force {
    public static void main(String[] args){
        //随机产生两个20位的二进制数字
        int n = 20;
        long value1 = (long)(Math.random()*Math.pow(2,n-1)+Math.pow(2,n-1));
        long value2 = (long)(Math.random()*Math.pow(2,n-1)+Math.pow(2,n-1));


        System.out.println("value1:"+ Long.toBinaryString(value1));

        System.out.println("value2:"+ Long.toBinaryString(value2));

        String temp1 = Long.toBinaryString(value1);
        String temp2 = Long.toBinaryString(value2);
        //将二进制数字表示成字符数组的形式
        char[] input1 = temp1.toCharArray();
        char[] input2 = temp2.toCharArray();
        
        System.out.println(Character.getNumericValue(input1[1]));
        long sum = 0;
        //暴力法求解
        for(int i = 0; i< input1.length; ++i){
            for(int j = 0; j< input2.length; ++j){
                sum += (Character.getNumericValue(input1[j]) & Character.getNumericValue(input2[i]))* Math.pow(2,i+j);
            }
        }
        System.out.println("result:"+ Long.toBinaryString(sum));
    }
}

2、分治法
  • 代码
public class BigNumber_Divide {
    public static void main(String[] args){
        //产生20位的二进制数
        int n = 20;
        long value1 = (long)(Math.random()*Math.pow(2,n-1)+Math.pow(2,n-1));
        long value2 = (long)(Math.random()*Math.pow(2,n-1)+Math.pow(2,n-1));


        System.out.println("value1:"+ Long.toBinaryString(value1));

        System.out.println("value2:"+ Long.toBinaryString(value2));

        String input1 = Long.toBinaryString(value1);
        String input2 = Long.toBinaryString(value2);
        long result = Divide(input1, input2);
        System.out.println(Long.toBinaryString(result));
    }
    //分治法划分二进制数字
    public static long Divide(String num1, String num2){
        if(num1.length() == 1 || num2.length() == 1){
            return Long.parseLong(num1) & Long.parseLong(num2);
        }
        int length1 = num1.length();
        int lenght2 = num2.length();
        //确定划分标准
        int mid = Math.max(lenght2,length1)/2;

        //AB * CD = AC * 2^n + (BC + AD) * 2^(n/2) + BD
        //确定A,B,C,D
        String a = num1.substring(0, mid);
        String b = num1.substring(mid);
        String c = num2.substring(0,mid);
        String d = num2.substring(mid);
        
        //求解子问题的解
        long z2 = Divide(a, c);
        long z0 = Divide(b,d);
        long z1 = Divide(a,c) - z2 - z0;

        //合并子问题
        return (long)(z2*Math.pow(2, lenght2)+ z1*Math.pow(2, mid) + z0);
    }
}


  • 题目2 实现找到最近两个点的距离
  • 题目描述:给定一堆二维坐标点,找到距离最近的两个点的坐标
  • 算法思路:
  1. Brute-Force方法:即暴力破解法,循环求出所有点之间的距离,统计出最近的两个点的距离即可,算法的时间复杂度为O(n^2)。

  2. 分治法:将问题划分成子问题进行求解,那么使用分治法就得确定几个点:

    • 递归循环的终止条件
    • 子问题的划分的标准
    • 子问题怎么合并成整个问题

    这几个点就是整个分治法的代码逻辑,那么我们来一个一个确定下来

    • 子问题最小时可以是问题规模里面只有两个点的时候,我们就可以直接计算出来
    • 为了保证子问题的规模大致相同,我们得让子问题的点的个数相同,那么我们可以对问题的中的点按照X坐标进行排序,取中间X坐标的点作为问题划分的关键点
    • 子问题在合并成整个问题时,需要考虑一个问题就是,如果最短距离的两个点分别出现在两个子问题中的情况,针对这种情况的话,我们可以以关键点为中心,构建一个距离中心点的X长度为当前最小距离的区域,超出这个长度点我们可以直接忽略,因为如果两个点之间的X坐标的距离超过当前最小距离,那么这两个点的距离一定超过最小距离,同理Y轴坐标也是这样。所以我们在合并子问题的时候,需要再多做这样一步操作,来防止上述情况的发生,这也是本道题的难点之一。具体的实现看代码即可。

  • 暴力法
  • 代码实现
import javafx.scene.effect.Light;
import java.util.ArrayList;
public class MinDistance_Brute_force {
    public static void main(String[] args){
        //构建1000个坐标点,保证坐标点不重复
        Point[] points = new Point[1000];
        ArrayList<Integer> list_x = new ArrayList<>();
        ArrayList<Integer> list_y = new ArrayList<>();
        while (list_x.size()<=1000){
            if(!list_x.contains((int)(Math.random()*100000))){
                list_x.add((int)(Math.random()*100000));
            }
        }
        while (list_y.size()<=1000){
            if(!list_y.contains((int)(Math.random()*100000))){
                list_y.add((int)(Math.random()*100000));
            }
        }
        for (int i = 0; i< 1000; ++i){
            points[i] = new Point(list_x.get(i), list_y.get(i));
        }
        //计算所有两个点之间的距离,记录最小值
        double minDis = Integer.MAX_VALUE;
        for(int i = 0; i< points.length; ++i){
            for(int j = i+1; j< points.length; ++j){
                if(Distance(points[i], points[j]) < minDis){
                    minDis = Distance(points[i], points[j]);
                }
            }
        }
        System.out.println(minDis);
    }
    public static double Distance(Point p1, Point p2){
        return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y- p2.y, 2));
    }
}
//构建一个坐标点
class Point{
    int x, y;
    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
  • 分治法求解
  • 代码实现
//import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Comparator;
import java.util.ArrayList;

public class MinDistance {
    public static void main(String[] args) {
        //随机产生1000个坐标不重复的点
        Point[] points = new Point[1000];
        ArrayList<Integer> list_x = new ArrayList<>();
        ArrayList<Integer> list_y = new ArrayList<>();
        while (list_x.size()<=1000){
            if(!list_x.contains((int)(Math.random()*10000))){
                list_x.add((int)(Math.random()*10000));
            }
        }
        while (list_y.size()<=1000){
            if(!list_y.contains((int)(Math.random()*10000))){
                list_y.add((int)(Math.random()*10000));
            }
        }

        for (int i = 0; i< 1000; ++i){
            points[i] = new Point(list_x.get(i), list_y.get(i));
        }
        //System.out.println(points);
        for(Point temp:points){
            System.out.println("X:"+temp.x+" Y:"+ temp.y);
        }
        //对点进行以X坐标大小进行排序
        Arrays.sort(points, new Comparator<Point>() {
            @Override
            public int compare(Point o1, Point o2) {
                return (o1.x > o2.x)? 1: (o1.x == o2.x)?0:-1;
            }
        });
        //分治法调用
        System.out.println(divide(points,0,points.length-1));
    }

    public static double divide(Point[] points, int left, int right){
        //终止条件1
        if(left == right){
            return Integer.MIN_VALUE;
        }
        //终止条件2
        if(right - left == 1){
            return Distance(points[left], points[right]);
        }
        //子问题的划分
        int mid = (left + right)/2;
        double left_min = divide(points, left, mid);
        double right_min = divide(points, mid, right);
        double min_dis = left_min<right_min?left_min:right_min;
        
        //子问题合并过程中需要防止两个点分别在子问题中
        ArrayList<Point> temp = new ArrayList<Point>();
        for(int i = left ; i< right - left; ++i) {
            if (points[mid].x - points[i].x < min_dis && Math.abs(points[mid].y - points[i].y) < min_dis) {
                temp.add(points[i]);
            }
        }
        for(int i = 0; i< temp.size(); ++i){
            for(int j = i+1; j< temp.size();++j){
                if(min_dis > Distance(temp.get(i), temp.get(j))){
                    min_dis = Distance(temp.get(i),temp.get(j));
                }
            }
        }
        return min_dis;
    }
    public static double Distance(Point p1, Point p2){
        return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y- p2.y, 2));
    }

}
class Point {
    public int x, y;
    Point(int x, int y){
        this.x = x;
        this.y = y;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值