博主也是第一次当博主,想要做一名名副其实的程序员,当然本质可能还是个商科生,看到博客的朋友可以一起交流经验,wechat:LYI_1998
1.二维数组中的查找
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
解题思路:
从左下角开始找,左下角的值m依据题目可得,m是行中最小,列中最大,故每次都将m与目标值target比较:
1.当m<target时,由于m为列中最大,故取值右移一位
2.当m>target时,由于m为行中最小,故取值向上移动一位
3.当m=target时,找到该值,返回true
每次比较都可以剔除一行或一列
代码:
package offer;
public class offer_1 {
public boolean Find(int target, int[][] array) {
// row:行;cols:列
int rows = array.length;
if (rows == 0) {
return false;
}
int cols = array[0].length;
if (cols == 0) {
return false;
}
int row = rows - 1;
int col = 0;
while (row >= 0 && col < cols) {
if (array[row][col] < target) {
col++;
} else if (array[row][col] > target) {
row--;
} else {
return true;
}
}
return false;
}
}
时间复杂度:O(行+列)
空间复杂度:O(1)
2.数组中重复的数
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
思路:
数组长度为n,则所有数字都在0~n-1中,则其实每个数都有专属自己的位置,如果有多个数在同一位置,即重复项。
例如:从下标i开始,比较下标i上的数字m是否与i相等:
若相等,则i++,接着比较;
若不相等,则数字m与下标m上的数进行比较,再若这两个数字相等,则重复;若不相等,则将数字m与下标m的数字交换位置,使m处于第m位,再重复比较交换过程,直到发现重复的数字。
代码:
package offer;
public class offer_2 {
// Alt+shift+j实现注释
/**
* @param nums
* @param length
* @param duplication
* @return
*/
public static boolean duplicate(int nums[], int length, int[] duplication) {
if (nums == null || length <= 0) {
return false;
}
for (int a : nums) {
if (a < 0 || a >= length) {
return false;
}
}
int temp;
for (int i = 0; i < length; i++) {
// 下标为i位置上的元素不为i
while (nums[i] != i) {
// 判断下标为nums[i]位置上的元素值是否为nums[i]
if (nums[nums[i]] == nums[i]) {
// 若下标为nums[i]上的值等于nums[i],则说明数字重复
duplication[0] = nums[i];
return true;
}
// 将下标为i和下标为nums[i]位置上的元素交换位置
temp = nums[i];
nums[i] = nums[temp];
nums[temp] = temp;
}
}
return false;
}
// 测试用例
public static void test_1() {
System.out.print("test_1:");
int[] a = { 3, 2, 2, 3, 4, 5 };
int[] dup = new int[a.length];
boolean result = duplicate(a, a.length, dup);
System.out.println(result);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
test_1();
}
}
时间复杂度:O(n)
空间复杂度:O(1)
3.题2的变式:不修改数组找出重复的数字
题目:
在一个长度为n+1的数组里的所有数字都在1~n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但是不能修改输入的数组。例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应的输出是重复的数字2或者3
分析:
可以用二分查找法,或者新建辅助数组,再一一对比下标上的数与对应数是否相等,流程和题目二基本相等。
代码:
package offer;
public class offer_2_1 {
public int getDup(int arr[]) {
int[] tempArr = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
if (arr[i] < 0 || arr[i] >= arr.length) {
throw new IllegalArgumentException("输入参数不合法");
} else {
tempArr[i] = -1;
}
}
for (int i = 0; i < arr.length; i++) {
if (tempArr[arr[i]] != arr[i]) {
tempArr[arr[i]] = arr[i];
} else {
return arr[i];
}
}
return -1;
}
public static void main(String[] args) {
offer_2_1 findrepeat = new offer_2_1();
int[] arr = { 3, 4, 5, 3, 2, 3, 5, 6, 5, 4, 5 };
int value = findrepeat.getDup(arr);
System.out.println(value);
}
}
时间复杂度:O(n)
空间复杂度:O(n)
4.构建乘积数组
题目:给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1]。不能使用除法。(注意:规定B[0] = A[1] * A[2] * … * A[n-1],B[n-1] = A[0] * A[1] * … * A[n-2];)
分析:
时间复杂度为:O(N)
可以把B[i]=A[0]A[1]…A[i-1]A[i+1]…A[n-1]。看成A[0]A[1]…A[i-1]和A[i+1]…A[n-2]A[n-1]两部分的乘积。即通过A[i]项将B[i]分为两部分的乘积。效果相当于是个对角矩阵。
package offer;
import java.util.Arrays;
public class offer_3 {
public static int[] multiply(int[] A) {
int length = A.length;
int[] B = new int[length];
// 边界
if (A == null || A.length <= 1) {
return null;
}
// 计算下三角
// 初始化第一行
B[0] = 1;
for(int i =1;i<length;i++) {
B[i]=B[i-1]*A[i-1];
}
// 计算上三角
// 初始化最后一行
int temp = 1;
for(int i=length-1;i>=0;i--) {
B[i]=temp*B[i];
temp=A[i]*temp;
}
return B;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] array_1 = {1,2,3,4,5};
System.out.println(Arrays.toString(multiply(array_1)));
int[] array_2 = {1,2,5,4,5};
System.out.println(Arrays.toString(multiply(array_2)));
int[] array_3 = {1,-2,3,4,-5};
System.out.println(Arrays.toString(multiply(array_3)));
}
}