努力经营当下,直至未来明朗!
普通小孩也要热爱生活!
1. 二维数组中的查找:[矩阵]
二维数组中的查找
1)查找的过程,本质是排除的过程。
2)找临界值:最大、最小
3)临界条件:合法范围中
4)根据大小比较排除行or列
代码:
public class Solution {
public boolean Find(int target, int [][] array) {
int i = 0; //行
int j = array[0].length -1; //第一行最后一个数字
// 合法范围条件
while(i<array.length && j>=0) {
if(target > array[i][j]) {
// 说明应该在下一行
i++;
} else if(target < array[i][j]) {
// 说明应该在前一列
j--;
} else {
return true;
}
}
return false;
}
}
2. 二分查找:旋转数组的最小数
旋转数组的最小数字
1)右移>>1 ;相当于/2
2)left、right、mid
3)注意题给:非递减(前<=后)
4)建议使用right判断,避免遗漏顺序的情况!
代码:
① 方法一:分的比较详细
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
// 首先判定是否有元素
if(array== null || array.length==0) {
return 0;
}
int left = 0;
int right = array.length-1;
int mid = 0;
while(left < right) {
if(right - left == 1) {
if(array[left] > array[right]) {
mid = right;
} else{
mid = left;
}
break;
}
// 这里会有一种情况,左中右相等,此时无法判断min是在左or右,则进行线性判断
mid = left + ((right-left)>>1);
if(array[left]==array[right] && array[left]==array[mid]) {
// 直接进行线性查找min
int ret = array[left];
for(int i=left+1; i<right; i++) {
if(ret > array[i]) {
ret = array[i];
}
}
return ret;
}
if(array[mid] > array[right]) {
// 说明此时最小的一定是在mid之后,前面一直在非递减
left = mid;
} else {
// 说明mid及之后是在非递减的,mid及之前一定会存在最小值
right = mid;
}
}
return array[mid];
}
}
② 方法二:
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
int left = 0;
int right = array.length-1;
// 首先进行判空
if(array==null || array.length==0) {
return 0;
}
// 循环判断:
while(left < right) {
int mid = left + ((right-left)>>1);
// 使用右边判断(否则可能会遗漏1 2 2 2 2 2顺序情况)
if(array[mid] > array[right]) {
// 在右边!
left = mid+1;
} else if(array[mid] < array[right]) {
// 在左边
right = mid;
} else {
// 此时进行线性遍历
right--;
}
}
return array[left];
}
}
3. 奇偶交换问题:(面试概率大)
调整数组顺序使奇数位于偶数前面
1)难点:奇数与奇数、偶数与偶数之间的相对位置不变!
2)相对位置可以变化:直接在原数组上进行操作就行,使用前后指针
3)补充:判断是否为奇数——可以使用该数&1,如果结果为1就是奇数,否则偶数
4)相对位置不变:使用 “插入” 的思想——从前往后遍历,遇到奇数时,将此前的所有偶数后移一个位置
代码:
① 方法一:从前往后,遇见奇数后将其前面的偶数全部后移一位:
public class Solution {
public void reOrderArray(int [] array) {
// 使用插入的思想
if(array==null || array.length==0) {
return;
}
int k = 0; // 记录奇数下标
for(int i=0; i<array.length; i++) {
// 如果遇到奇数
if((array[i]&1) == 1) { // 此时说明是奇数
// 在此之前所有的偶数后移一个位置,给奇数腾空间
int j = i; // 保存该奇数的下标
int tmp = array[i]; // 保存该奇数
while(j > k) { //移动的偶数绝对在上一个奇数位置之后
// 之前的偶数全部后移一个位置
array[j] = array[j-1];
j--;
}
array[k++] = tmp;
}
}
}
}
② 方法二:从后往前,遇见偶数后将其后面的奇数全部前移一位:
public class Solution {
public void reOrderArray(int [] array) {
if(array==null || array.length==0) {
return;
}
int k = array.length-1;
for(int i=array.length-1; i>=0; i--) {
if((array[i]&1)==0) { // 偶数
// 记录位置以及该值
int j = i;
int tmp = array[i];
// 将前面的all奇数往前移动一位
while(j < k) {
array[j] = array[j+1];
j++;
}
array[k--] = tmp;
}
}
}
}
4. 出现次数超过一半的数
数组中出现次数超过一半的数字
思路:①定义HashMap,并找次数最大的比较half(但是空间复杂度较大); ②排序算法,中间位置; ③同时去掉不一样的两个数:出现次数抵消策略+次数再统计(重点!)
代码:
① 方法一:使用HashMap
import java.util.HashMap;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
int half = array.length / 2;
// 方法一:HashMap法
HashMap<Integer,Integer> map = new HashMap<>();
for(int i=0; i<array.length; i++) {
if(map.get(array[i]) == null) {
map.put(array[i],1);
} else {
map.put(array[i],map.get(array[i])+1);
}
}
for(int i=0; i<array.length; i++) {
if(map.get(array[i]) > half) {
return array[i];
}
}
return 0;
}
}
② 方法二:次数相消法(两个for循环串行,so:时间复杂度就是O(N))
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
// 方法二:次数相消法
int half = array.length / 2;
int target = array[0];
int times = 0; // 这里是0
for(int i=0; i<array.length; i++) {
if(times == 0) {
// 更新target/times
target = array[i];
times = 1; // 这里是1
} else if(target == array[i]) {
times++;
} else {
times--;
}
}
// 最后再遍历确定到底是不是大于一半(double check)
times = 0;
for(int i=0; i<array.length; i++) {
if(target == array[i]) {
times++;
}
}
return (times>half)? target:0;
}
}