303. 区域和检索 - 数组不可变
给定一个整数数组 nums,求出数组从索引 i 到 j(i ≤ j)范围内元素的总和,包含 i、j 两点。
实现 NumArray 类:
- NumArray(int[] nums) 使用数组 nums 初始化对象
- int sumRange(int i, int j) 返回数组 nums 从索引 i 到 j(i ≤ j)范围内元素的总和,包含 i、j 两点(也就是 sum(nums[i], nums[i + 1], … , nums[j]))
思路
1.这个题的一般解法如下:设置一个全局私有变量,第一个函数给该变量赋值,第二个函数进行求解操作。
class NumArray {
private int[] num;
public NumArray(int[] nums) {
this.num = nums;
}
public int sumRange(int i, int j) {
int sum = 0;
for(int k = i; k <= j; k++) {
sum += this.num[k];
}
return sum;
}
}
2.但是这个题的最优解答是前缀和。
前缀和是一个数组的某项下标之前(包括此项元素)的所有数组元素的和。
因此我们设置一个数组s,用来存储前缀元素的和。从而i到j的和大小即为:s[j]-s[i]
错误
在考虑第二个思路的时候,容易忽略:对于第一个数来说,它的前缀和是0。因此,用于存储前缀和的数组长度应该是原数组长度 + 1.
又因为结果要包含i,j对应元素,所以sum[j + 1] - sum[i];
完整代码
private int[] sum;
public NumArray(int[] nums) {
sum = new int[nums.length + 1];
for(int i = 0; i < nums.length; i++) {
sum[i + 1] = nums[i] + sum[i];
}
}
public int sumRange(int i, int j) {
return sum[j + 1] - sum[i];
}
4. 寻找两个正序数组的中位数(一)
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
思路
1.暴力解法,新建一个大小等于两数组长度之和的数组,然后按正序复制,求出中位数。
2.再思考之后,因为两个数组都是正序的,所以中位数的位置是知道的。只需要维护两个指针,比大小移动即可。
错误
i < m && (j >= n ||nums1[i] < nums2[j])
在上述条件中||形成了短路,所以要是颠倒括号中的顺序,那么会造成数组越界
完整代码
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
int i = 0;
int j = 0;
int left = -1;
int right = -1;
for(int k = 0; k <= (m + n) / 2; k++) {
left = right;
if(i < m && (j >= n ||nums1[i] < nums2[j])) {
right = nums1[i++];
}else {
right = nums2[j++];
}
}
if((m + n) % 2 == 0) {
return (double)(left + right) / 2;
}else {
return (double)right;
}
}
但是这个题的进阶要求写到o(log(m + n)),使用二分法。后面对二分法进行学习。
9. 回文数
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。
思路
排除掉数字为负数的情况
将数字从int类型转换成为string类型
完整代码
public boolean isPalindrome(int x) {
if(x < 0) {
return false;
}
String s = String.valueOf(x);
int i = 0;
int j = s.length() - 1;
while(i <= j) {
if(s.charAt(i) == s.charAt(j)) {
i++;
j--;
}else {
return false;
}
}
return true;
}