【算法】Day01:数组

努力经营当下,直至未来明朗!


普通小孩也要热爱生活!

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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

'Dream是普通小孩耶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值