万物的算法日记|第四天

笔者自述:

一直有一个声音也一直能听到身边的大佬经常说,要把算法学习搞好,一定要重视平时的算法学习,虽然每天也在学算法,但是感觉自己一直在假装努力表面功夫骗了自己,没有规划好自己的算法学习和总结,因为后半年也该找实习了,所以每日的算法题要进行恶补,勤能补拙,因此有了这一个算法日记系列;

必读: 大佬你好,感谢您的阅读,这篇文章是我的算法笔记,方便我每日回顾;
为了不耽误您的时间,我把本篇日记的考点方向和算法知识总结列出来,如果对您有需要就继续向下进行阅读

也希望对您有帮助,和您一起通关算法!致谢

请添加图片描述

算法语言:java
题目来源:力扣–书本–初级算法,可以在力扣中搜索相关题名找到更多解法和大神方法
本文知识点:

  1. Hashset和Hashmap讲解

HashSet讲解: 不允许有重复元素,内部无序,由散列表实现,支持快速的查询,插入和删除。
适用场景:需要去除重复元素,不需要有序遍历元素,对元素的增删改查时间复杂度要求是O(1)情况
方法: set.add() set.delete() set.contains() set.size()
缺点:因为无序,所有空间利用率较低,最坏情况,所有元素映射到同一个散列桶内,时间复杂度退化为O(n)

HashMap讲解:键值对形式,允许空建和空值,根据键值快速查找,最优情况增删改查为O(1)
适用场景:根据键值快速增删改查,需要快速遍历映射表中的所有元素,时间复杂度最优为O(1)
方法:map.put(key,value) map.remove(key) map.containsKey(key) map.size() 遍历映射:遍历map中的key结合或者entry集合
缺点:在最坏情况下(所有键值都映射到同一个散列桶中),HashMap的时间复杂度将退化至O(N)。HashMap的性能取决于散列函数的质量。散列函数越好,冲突的概率就越低,HashMap的性能就越好

  1. 对于区间求数范围,可以使用二分法来确定区间的左右边界,因为二分法每次只能确定一个边界,所有可以使用两次二分法来确定左右边界
  2. 二叉搜索树: 左分支小于根节点,有分支大于根节点

    文章目录

    • 剑指 Offer 03. 数组中重复的数字
    • 剑指 Offer 53 - I. 在排序数组中查找数字 I
    • 剑指 Offer 53 - II. 0~n-1 中缺失的数字
    • 剑指 Offer 04. 二维数组中的查找

剑指 Offer 03. 数组中重复的数字

万物的算法日记|第四天_第1张图片
代码:

class Solution {
    public int findRepeatNumber1(int[] nums){
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int i:nums){
            if(map.containsKey(i)){
                return i;
            }else{
                map.put(i,1);
            }
        }
        return -1;
    }
    // 使用hashset 遇到相同的直接返回
    public int findRepeatNumber2(int[] nums){
        Set<Integer> dic = new HashSet<>();
        for(int num: nums){
            if(dic.contains(num)) return num;
            dic.add(num);
        }
        return -1;
    }
     //交换值,相当于hashmap的作用 充分使用题中的条件
    public  int findRepeatNumber(int[] nums){
        int i =0;
        while(i<nums.length){
            if(nums[i] == i){
                i++;
                continue;
            }
            if(nums[nums[i]] == nums[i]) return nums[i];
            int tmp = nums[i];
            nums[i] = nums[tmp];
            nums[tmp] = tmp;
        }
        return -1;
    }
}

学到的知识:

  1. Hashset和Hashmap讲解

HashSet讲解: 不允许有重复元素,内部无序,由散列表实现,支持快速的查询,插入和删除。
适用场景:需要去除重复元素,不需要有序遍历元素,对元素的增删改查时间复杂度要求是O(1)情况
方法: set.add() set.delete() set.contains() set.size()
缺点:因为无序,所有空间利用率较低,最坏情况,所有元素映射到同一个散列桶内,时间复杂度退化为O(n)

HashMap讲解:键值对形式,允许空建和空值,根据键值快速查找,最优情况增删改查为O(1)
适用场景:根据键值快速增删改查,需要快速遍历映射表中的所有元素,时间复杂度最优为O(1)
方法:map.put(key,value) map.remove(key) map.containsKey(key) map.size() 遍历映射:遍历map中的key结合或者entry集合
缺点:在最坏情况下(所有键值都映射到同一个散列桶中),HashMap的时间复杂度将退化至O(N)。HashMap的性能取决于散列函数的质量。散列函数越好,冲突的概率就越低,HashMap的性能就越好

剑指 Offer 53 - I. 在排序数组中查找数字 I

万物的算法日记|第四天_第2张图片
代码:

class Solution {
//使用二分法来进行查找目标值 因为二分法一次智能找到一个值
//如果要求范围的话 使用两次二分法来找到左右边界
  public int search1(int[] nums, int target) {
    if (nums.length <= 0) {
        return 0;
    }
    int left = 0, right = nums.length - 1;
    // 寻找左边界
    while (left <= right) {
        int mid = left + ((right - left) >> 1);
        if (nums[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    if (left >= nums.length || nums[left] != target) {
        // 如果找到的位置越界或者不是目标元素,则不存在目标元素
        return 0;
    }
    int left1 = left;
    left = 0;
    right = nums.length - 1;
    // 寻找右边界
    while (left <= right) {
        int mid = left + ((right - left) >> 1);
        if (nums[mid] > target) {
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }
    int right1 = right;
    return right1 - left1 + 1;
	}
 //方法二:使用hashmap来进行次数统计
    public int search(int[] nums,int target){
        HashMap<Integer,Integer> map = new HashMap<>();
        for (int num : nums) {
            if (map.containsKey(num))
                map.put(num, map.get(num)+1);
            else
                map.put(num, 1);
        }
        for(int i=0;i<map.size();i++){
            if(map.containsKey(target)){
                return map.get(target);
            }
        }
        return 0;
    }
}

学到的知识:

  1. 使用hashmap操作利用键值对的对应关系来存储次数,根据条件输出,很好的练手题
  2. 因为是排好序的,要求个数,可以求一个区间,使用二分查找找符合规定的数,因为二分查找一次只能找到一个数,所以使用两次二分来分别找到对应的左右边界,通过索引差就可以得到想要的数据。

剑指 Offer 53 - II. 0~n-1 中缺失的数字

万物的算法日记|第四天_第3张图片
代码:

class Solution {
     public int missingNumber1(int[] nums){
        //求和
        int sum = 0;
        int sum1 =0;
        for(int i =0;i<nums.length;i++){
            sum += nums[i];
        }
        for(int i =1;i<=nums.length;i++){
            sum1 +=i;
        }
        return sum1-sum;
    }

      //使用hashmap解决
    public int missingNumber2(int[] nums){
        HashMap<Integer,Integer> map = new HashMap<>();
        int length = nums.length;
        for(int i =0;i<nums.length;i++){
            map.put(nums[i],1);
        }
        for(int i =0;i<=nums.length;i++){
            if(!map.containsKey(i))
                return i;
        }
        return 0;
    }
    public int missingNumber(int[] nums){
        if(nums.length<=0){
            return 0;
        }
        int xor = 0;
        for(int i =0;i<nums.length;i++){
            xor = xor^nums[i]^(i+1);
        }
        return xor;
    }

}

学到的知识:

  1. 位运算真的很快,学会利用位运算很大程度上降低时间复杂度,上述我实现了三个方法,其中哈希表的时间复杂度最高,但是最容易理解,这道题我做了第二次了,拿到后思路仍然很凌乱,首先想到的是使用哈希表来解决问题,位运算挺好的,要多练习。

剑指 Offer 04. 二维数组中的查找

万物的算法日记|第四天_第4张图片

代码:

 public boolean findNumberIn2DArray(int[][] matrix,int target){
        //使用双层for循环 可以求出 时间复杂度太高
        // 如何搜索 通过比对 范围 时间复杂度为O(N*M)
        boolean flag ;
        for(int i =0;i<matrix.length;i++){
            for(int j =0;j<matrix[0].length;j++){
                if(target == matrix[i][j]){
                    return true;
                }
            }
        }
        return false;
    }

    //使用二叉树的方法来进行实现
    public boolean findNumberIn2DArray1(int[][] matrix,int target){
        int i = matrix.length-1,j =0;
        while(i>=0&& j<matrix[0].length){
            if (matrix[i][j] >target){
                i--;
            }else if(matrix[i][j] <target){
                j++;
            }else{
                return true;
            }
        }
        return false;
    }

学到的知识:

  1. 二叉搜索树: 左分支小于根节点,有分支大于根节点
    可以通过二叉搜索的方式来找到目标值,通过移动i和j;同时也可以直接使用暴力方法来进行寻找。

你可能感兴趣的:(万物的算法日记,算法,数据结构)