数组篇
前言
本次算法入门训练主要训练以下三个内容:
- 以特殊数据结构为载体的算法结构,比如:数组、链表、栈、二叉树等
- 以考察常见算法思想基础的算法题,比如:动态规划、贪心、回溯等
- 基于某种场景包装下的1和2
提示:以下是本篇文章正文内容
内容
第一题:二维数组中的查找
解题思路:这题的主要思路就是观察题目的特性,要注意到右上角和左下角位置的特殊性,排除这里的元素就可以排除一列或者一行。(查找的本质就是排除,相比于一个一个排除,显然一次排除一堆效率更高)
OJ链接:第一题
import java.util.ArrayList;
public class Solution {
public boolean Find(int target, ArrayList<ArrayList<Integer>> array) {
//二维数组的右上角是当前列的最小值,当前行的最大值
//左下角是当前列的最大值,当前行的最小值
//始终定位右上角
int i = 0;
int j = array.get(0).size() - 1;
while(i < array.size() && j >= 0){
if(array.get(i).get(j) > target){
//说明当前列中没有目标值
//排除掉当前列
j--;
}else if (array.get(i).get(j) < target){
//说明当前行没有目标值
//排除掉当前行
i++;
}else{
//找到了
return true;
}
}
//没找到
return false;
}
}
第二题:旋转数组的最小数字
解题思路:方法一,遍历一次即可,旋转之后的数组有两段非递减序列,但是他们相交的地方是递减的只需要找到递减数字就是最小值。方法二,二分查找,定义首尾下标,因为是非递减数组旋转,所以旋转最后可以看做成两部分,前半部分整体非递减,后半部分整体非递减,前半部分整体大于后半部分。然后确定中间位置,中间位置要么在前半部分要么在后半部分,再前半部分范围就向后缩小,在后半部分就向前缩小。
OJ链接:第二题
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(ArrayList<Integer> array) {
//旋转后数组分为两部分,两部分都是非递减序列
if (array == null || array.size() == 0) {
return 0;
}
int left = 0;
int right = array.size() - 1;
int mid = 0;
while (array.get(left) >= array.get(right)) {
//结束条件 当left和right相邻时,right就是最小值
if (right - left == 1) {
mid = right;
break;
}
mid = (left + right) >> 1;
//据题意可能出现array[mid] == array[left] == array[right],这时就直接线性探测
if (array.get(mid) == array.get(left) && array.get(left) == array.get(right)) {
int result = array.get(left);
for (int i = left + 1; i < right; i++) {
if (result > array.get(i)) {
result = array.get(i);
}
}
return result;
}
//当mid在前半部分时,说明array[mid] > array[left],最小值在后半部分,范围向后缩小
//当mid在后半部分时,说明array[mid] < array[left],最小值在前半部分,范围向前缩小
if (array.get(mid) >= array.get(left)) {
left = mid;
} else {
right = mid;
}
}
return array.get(mid);
}
}
第三题:调整数组顺序使奇数位于偶数前面
解题思路:找到奇数,如果奇数前有偶数,保存奇数再把奇数前的偶数全部往后移位给奇数腾出位置。
OJ链接:第三题
import java.util.*;
public class Solution {
public void reOrderArray(int[] array) {
int k = 0;
for(int i = 0; i < array.length; i++){
if((array[i] & 1) == 1){
//奇数
//保存它的值和位置
int tmp = array[i];
int j = i;
//当前奇数和奇数序列之间有偶数就把所有偶数向后移
while(j > k){
array[j] = array[j-1];
j--;
}
array[k++] = tmp;
}
}
}
}
第四题:数组中出现次数超过一半的数字
解题思路:方法一,给数组排序,那么中间位置一定就是那个超过一半的数字。方法二,定义map统计数字出现的次数。方法三,每次删掉两个不同的元素,最后剩下的两个元素或者一个元素就是次数超过一半的数字,得到数字需要进行验证,可能出现没有这个数字的情况。
OJ链接:第四题
import java.util.*;
public class Solution {
public int MoreThanHalfNum_Solution(ArrayList<Integer> array) {
//每次删掉两个不同的元素的,最后剩下的两个元素或者一个元素就是次数超过一半的数字
//得到数字需要进行验证,可能出现没有这个数字的情况
//拿出第一个数字进行比较,如果该数字被删掉了,后续上来的第一个数字进行补充
int times = 1;//被比较数字的个数
int target = array.get(0);//被其它数字比较的数字
for(int i = 1; i < array.size(); i++){
//times = 0 说明被比较的数字被删掉了,需要更新数字
if(times == 0){
target = array.get(i);
times = 1;
}
if(array.get(i) != target){
times--;
}else{
times++;
}
}
//进行验证
times = 0;
for(int i = 0; i < array.size(); i++){
if(array.get(i) == target){
times++;
}
}
return times > array.size() / 2 ? target : 0;
}
}
总结
以上就是今天训练的内容,今天的题除了第二题稍微有一点难度其它的都挺好写的,数组是题量最多的一种算法结构了,需要多多练习。