最近疫情好严重,一周没出门了,今年过年也不串亲戚了,这样也很清静,安心下来学习就好了。
关于数据结构与算法,基础比较差,感觉还是比较艰辛的,一道题目需要花几个小时才能差不多掌握了。
目前感觉,学习解算法题可以分为这几个程度:
- 解出题目:这是最基础的,对于基础算法题,也比较容易解出来。比如这道题,找到第一个数字和后面一个一个比,然后再换第二个重复操作,直到遍历完,这种很好想,但效率是O(n^2),解的就比较蠢了。
- 多种方法:算法题都会有很多种解法的,这对于我就比较挑战了。比如用排序,散列表等等,基本的一些方法需要多留意了。
- 最优方法:这设计到方法的比较和选择了。这就很有挑战了,如何找到时/空复杂度都比较好的算法?答案提供的思路都很漂亮,但如何能想到这种思路呢?
- 细节部分:以上是大思路,还有很多的细节可以优化,小到一些标识符更规范的命名,各种测试用例的情况都要考虑到。比如如果出现两次以上的重复数据,答案需要只输出一次。
完成第1步半个小时就可以了,但到第2步就得一个小时以上,只分析还好,自己都实现出来时间就要更久了。完成之后的要求需要的时间就更长了,但时间就那么多。
所以目前来看每道题不要超过两个小时,边学边练,一天掌握一道题也不错了。书上的方法都要实现一遍,比较难得的先理解一下思路,然后把书上的代码一行行理解的编下来,做题多了选择方法的时候就会有印象或者有感觉了,细节部分慢慢完善。
题目部分:
public class Array1 {
/* 找出数组中重复的数字。'
在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某
些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了
几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7的数
组{2, 3, 1, 0, 2, 5, 3},那么对应的输出是重复的数字2或者3 */
public static void main(String[] args) {
int[] arr1 = {2, 1, 3, 0, 2, 5, 3}; // 有重复数字
int[] arr2 = {0, 1, 2, 3, 4, 5, 6}; // 无重复数字
int[] arr3 = {7}; // 数据不合理
duplicate3(arr1);
}
// 普通方法,时间效率O(n^2)
public static void duplicate0(int[] arr) {
for(int i = 0; i < arr.length; i++) {
if(arr[i] < 0 || arr[i] >= arr.length) {
System.out.println("error!"); // 无效输入测试用例
}
for( int j = i+1; j < arr.length; j++) {
if(arr[i] == arr[j]){
System.out.println(arr[i]); // 输出重复数字
break;
}
}
}
}
//排序算法,时间效率O(nlogn)
public static void duplicate1(int[] arr) {
quickSort(arr, 0, arr.length-1);
int dup = -1;
for(int i = 0; i <= arr.length-2; i++) {
if(arr[i] < 0 || arr[i] >= arr.length) {
System.out.println("error!"); // 无效输入测试用例
}
if(arr[i] == dup) {
continue; // 多次重复的数字只输出一次
}
if(arr[i] == arr[i+1]) {
dup = arr[i]; // 记录重复数字
System.out.println(arr[i]); // 输出重复数字
}
}
}
public static void quickSort(int[] arr,int low,int high){ // 略 }
//哈希表,时间效率O(n),空间占用O(n)
public static void duplicate2(int[] arr) {
int[] arr0 = new int[arr.length];
int value;
for(int i = 0; i < arr.length; i++) {
if(arr[i] < 0 || arr[i] >= arr.length) {
System.out.println("error!"); // 无效输入测试用例
return;
}
value = arr0[arr[i]];
if(value == 0) {
arr0[arr[i]] = value + 1; // 记录新值
}else if(value == 1) {
arr0[arr[i]] = value + 1;
System.out.println(arr[i]); // 输出重复值
}
}
}
// 剑指Offer解法:数字是有范围的(0~n-1),遍历时把数字交换至对应大小的下标处
// 时间复杂度:O(n),遍历一遍,每个数字最多交换两次
// 空间复杂度:O(1)
public static void duplicate3(int[] arr) {
for(int i = 0; i < arr.length; i++ ) {
// 数据合理性检查
if(arr[i] < 0 || arr[i] > arr.length -1) {
System.out.println("error!"); // 无效输入测试用例
return;
}
// 查找重复数据
while(arr[i] != i) {
if(arr[arr[i]] == arr[i]) {
// 位置已有元素,说明重复
System.out.println(arr[i]);
break;
}else {
// 交换位置
int temp = arr[arr[i]];
arr[arr[i]] = arr[i];
arr[i] = temp;
}
}
}
}
}