常见数据结构与算法二

目录

x的平方根

解法一:二分查找

解法二:牛顿迭代(牛顿-拉弗森方法)

三个数的最大乘积

解法一:排序

解法二:线性扫描


x的平方根

在不使用 sqrt(x) 函数的情况下,得到 x的平方根的整数部分

解法一:二分查找

public static int binarySearch (int x) {
        int left = 0, right = x, index = -1;
        while (left <= right) {
            int middle = left + (right - left) / 2;
            if ((long)middle * middle <= x) {
                index = middle;
                left = middle + 1;
            } else {
                right = middle -1;
            }
        }
        return index;
}

方法的逻辑如下:

  1. 定义两个指针 left 和 right,分别初始化为 0 和 x。这两个指针将用来在可能的平方根值的范围内进行搜索。index 被初始化为 -1,用来存储最终的结果。

  2. 使用 while 循环进行二分查找,条件是 left 小于等于 right

  3. 在每次迭代中,计算 middle,它是 left 和 right 的中间值。为了防止整数溢出,这里使用 left + (right - left) / 2 而不是 (left + right) / 2

  4. 接下来,检查 middle * middle 是否小于或等于 x

    • 如果是,这意味着 middle 可能是 x 的平方根的整数部分,或者还有更大的值。因此,将 index 设置为 middle,然后将 left 移动到 middle + 1,以便在更大的值中继续搜索。
    • 如果不是,这意味着 middle 太大了,我们需要在更小的值中搜索,所以将 right 设置为 middle - 1
  5. 当 left 大于 right 时,循环结束,此时 index 存储的是满足条件的最大整数。

  6. 返回 index 作为结果。

解法二:牛顿迭代(牛顿-拉弗森方法)

public static int newton (int x) {
        if (x == 0) return 0;
        return ((int)(sqrts(x, x)));
    }

    public static double sqrts (double i, int x) {
        double result = (i + x / i) / 2;
        if (result == i) {
            return i;
        } else {
            return sqrts(result, x);
        }
    }

牛顿迭代法是一种数值计算方法,可以用来求解函数的零点,也就是使得函数值为零的点。在这个例子中,我们使用它来求解 f(i) = i^2 - x 的零点,这个零点就是 x 的平方根。

这个算法的基本思想是从一个初始猜测值 i 开始,然后不断迭代更新这个猜测值,使其越来越接近真实的平方根值。

具体来说,这段代码包含了两个方法:

  1. newton 方法:这是主方法,用于处理特殊情况并启动迭代过程。

    • 如果 x 是 0,那么直接返回 0,因为 0 的平方根就是 0
    • 调用 sqrts 方法,并将结果强制转换为 int 类型,以得到平方根的整数部分。
  2. sqrts 方法:这是递归方法,用于实际执行牛顿迭代。

    • 首先,计算当前猜测值 i 的一个更新值 result,使用牛顿迭代公式 (i + x / i) / 2
    • 然后,检查 result 是否和前一个猜测值 i 相等。如果相等,说明已经找到了一个足够接近的近似值,可以结束迭代。
    • 如果不相等,继续递归调用 sqrts 方法,使用新的猜测值 result

三个数的最大乘积

一个整型数组 nums ,在数组中找出由三个数字组成的最大乘积,并输出这个乘积。

分析:
如果数组中全是非负数,则排序后最大的三个数相乘即为最大乘积;如果全是非正数,则最大的三个数相乘同样也为最大乘积。
如果数组中有正数有负数,则最大乘积既可能是三个最大正数的乘积,也可能是两个最小负数(即绝对值最大)与最大正数的乘积。
分别求出三个最大正数的乘积,以及两个最小负数与最大正数的乘积,二者之间的最大值即为所求答案。

解法一:排序

public static int sort (int[] nums) {
        Arrays.sort(nums);
        int n = nums.length;
        return Math.max(nums[0] * nums[1] * nums[n - 1], nums[n - 3] * nums[n - 2] * nums[n -1]);
}

方法的逻辑如下:

  1. 使用 Arrays.sort(nums) 对数组进行排序。排序后,数组的元素将按升序排列。

  2. 获取排序后的数组长度 n

  3. 计算两种可能的三个数字的乘积:

    • nums[0] * nums[1] * nums[n - 1]:这是最小的两个数(可能是负数)和最大的一个数的乘积。
    • nums[n - 3] * nums[n - 2] * nums[n - 1]:这是最大的三个数的乘积。
  4. 使用 Math.max 函数比较这两种乘积,返回较大的那个作为结果。

解法二:线性扫描

public static int getMaxMin (int[] nums) {
        // 最小的和第二小的
        int min1 = 0, min2 = 0;
        // 最大的、第二大的和第三大的
        int max1 = 0, max2 = 0, max3 = 0;
        for (int x : nums) {
            if (x < min1) {
                min2 = min1;
                min1 = x;
            } else if (x < min2) {
                min2 = x;
            }

            if (x > max1) {
                max3 = max2;
                max2 = max1;
                max1 = x;
            } else if (x > max2) {
                max3 = max2;
                max2 = x;
            } else if (x > max3) {
                max3 = x;
            }
        }
        return Math.max(min1 * min2 * max1, max1 * max2 * max3 );
    }

方法的逻辑如下:

  1. 初始化两个变量 min1 和 min2 来存储数组中的最小值和第二小的值。同时,初始化 max1max2 和 max3 来存储数组中的最大值、第二大的值和第三大的值。

  2. 遍历数组 nums 中的每个元素 x

    • 如果 x 小于 min1(当前最小值),则更新 min1 和 min2min2 变为原来的 min1min1 变为新的 x)。
    • 否则,如果 x 小于 min2,则只更新 min2
    • 如果 x 大于 max1(当前最大值),则更新 max1max2 和 max3max3 变为原来的 max2max2 变为原来的 max1max1 变为新的 x)。
    • 否则,如果 x 大于 max2,则更新 max2 和 max3max3 变为原来的 max2max2 变为新的 x)。
    • 否则,如果 x 大于 max3,则只更新 max3
  3. 计算两种可能的三个数字的乘积,并使用 Math.max 函数返回较大的那个乘积:

    • min1 * min2 * max1:这是最小的两个数和最大的一个数的乘积。
    • max1 * max2 * max3:这是最大的三个数的乘积。

  • 10
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值