目录
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;
}
方法的逻辑如下:
定义两个指针
left
和right
,分别初始化为0
和x
。这两个指针将用来在可能的平方根值的范围内进行搜索。index
被初始化为-1
,用来存储最终的结果。使用
while
循环进行二分查找,条件是left
小于等于right
。在每次迭代中,计算
middle
,它是left
和right
的中间值。为了防止整数溢出,这里使用left + (right - left) / 2
而不是(left + right) / 2
。接下来,检查
middle * middle
是否小于或等于x
:
- 如果是,这意味着
middle
可能是x
的平方根的整数部分,或者还有更大的值。因此,将index
设置为middle
,然后将left
移动到middle + 1
,以便在更大的值中继续搜索。- 如果不是,这意味着
middle
太大了,我们需要在更小的值中搜索,所以将right
设置为middle - 1
。当
left
大于right
时,循环结束,此时index
存储的是满足条件的最大整数。返回
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
开始,然后不断迭代更新这个猜测值,使其越来越接近真实的平方根值。具体来说,这段代码包含了两个方法:
newton
方法:这是主方法,用于处理特殊情况并启动迭代过程。
- 如果
x
是0
,那么直接返回0
,因为0
的平方根就是0
。- 调用
sqrts
方法,并将结果强制转换为int
类型,以得到平方根的整数部分。
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]);
}
方法的逻辑如下:
使用
Arrays.sort(nums)
对数组进行排序。排序后,数组的元素将按升序排列。获取排序后的数组长度
n
。计算两种可能的三个数字的乘积:
nums[0] * nums[1] * nums[n - 1]
:这是最小的两个数(可能是负数)和最大的一个数的乘积。nums[n - 3] * nums[n - 2] * nums[n - 1]
:这是最大的三个数的乘积。使用
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 );
}
方法的逻辑如下:
初始化两个变量
min1
和min2
来存储数组中的最小值和第二小的值。同时,初始化max1
、max2
和max3
来存储数组中的最大值、第二大的值和第三大的值。遍历数组
nums
中的每个元素x
:
- 如果
x
小于min1
(当前最小值),则更新min1
和min2
(min2
变为原来的min1
,min1
变为新的x
)。- 否则,如果
x
小于min2
,则只更新min2
。- 如果
x
大于max1
(当前最大值),则更新max1
、max2
和max3
(max3
变为原来的max2
,max2
变为原来的max1
,max1
变为新的x
)。- 否则,如果
x
大于max2
,则更新max2
和max3
(max3
变为原来的max2
,max2
变为新的x
)。- 否则,如果
x
大于max3
,则只更新max3
。计算两种可能的三个数字的乘积,并使用
Math.max
函数返回较大的那个乘积:
min1 * min2 * max1
:这是最小的两个数和最大的一个数的乘积。max1 * max2 * max3
:这是最大的三个数的乘积。