【练习】Day05

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


普通小孩也要热爱生活!

一、选择

  1. HASH 函数冲突处理方式不包括以下哪一项:()

A. 开放定址法
B. 链地址法
C. 插入排序法
D. 公共溢出区法

  1. HashMap的数据结构是怎样的?()

A. 数组
B. 链表
C. 数组+链表
D. 二叉树

  1. 以下程序的运行结果是( )
TreeSet<Integer> set = new TreeSet<Integer>();
TreeSet<Integer> subSet = new TreeSet<Integer>();
for(int i=606;i<613;i++){
	if(i%2==0){
		set.add(i);
	}
}
subSet = (TreeSet)set.subSet(608,true,611,true);
set.add(609);
System.out.println(set+" "+subSet);

A. 编译失败
B. 发生运行时异常
C. [606, 608, 609,610, 612] [608, 609,610]
D. [606, 608, 609,610, 612] [608, 610]

  1. 散列函数有共同的性质,则函数值应当以( )概率取其值域的每一个值。( )

A. 最大
B. 最小
C. 平均
D. 同等


二、编程

1. 跳跃游戏[贪心算法]

LeetCode45.跳跃游戏II
给你一个非负整数数组 nums ,你最初位于数组的第一个位置(也就是0下标)。数组中的每个元素代表你在该位置可以跳跃的最大长度
你的目标是使用最少的跳跃次数到达数组的最后一个位置。假设你总是可以到达数组的最后一个位置。


2. 寻找重复数[注意思路!]

LeetCode287.寻找重复数
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的
整数。
假设 nums 只有 一个重复的整数 ,找出 这个重复的数 。你设计的解决方案必须不修改数组 nums 且只用常量级 O(1) 的额外空间。


答案

1. 选择

  1. ① 插入排序是一种排序算法。
    ② Hash函数冲突的处理方法有:开放地址法,链地址法,再哈希法, 建立公共溢出区。
    ③ hash冲突的避免设计哈希函数(直接定制法、除留余数法、平方取中法、折叠法、随机数法、数字分析法)、调节负载因子
    解决 hash冲突:闭散列(开放定址法:线性探测、二次探测)、开散列/哈希通过(链地址法、开链法)、公共溢出区法。
    一定要区分“避免”和“解决”!!
    参考:Hash函数

故:选C

  1. HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对
    ② 数组的每一个元素上可以挂key值相同的链表元素链表主要为了解决哈希冲突而存在的

故:选C

  1. 【最难理解的就是:subSet = (TreeSet)set.subSet(608,true,611,true);
    set中存放的是一组不重复的数据集合,根据循环可以知道606~613这几个数据中,是2的倍数为606,608,610,612
    ② 最后set中add加入了609,所以set:[606, 608, 609,610, 612]
    java.util.TreeSet.subSet(E fromElement,boolean fromInclusive,E toElement,boolean toInclusive) 方法用于返回位于给定范围之间的一组元素

参数:
① fromElement:这是返回集的最小边界值
② fromInclusive:如果将最小边界值包含在返回的视图中,则为true。(决定是否包含边界值)
③ toElement:这是返回集的最大边界值。
④ toInclusive:如果要在返回的视图中包含最大边界值,则为true。
所以,set.subSet(608,true,611,true)返回的数为:[608, 609,610]

故:选C

  1. ① Hash函数的算法运算所取得的值应当尽可能均匀的分布,否则就会出现哈希冲突。
    ② 哈希冲突可以减少,但是是无法避免的。

故:选D:同等概率


2. 编程

  1. 跳跃游戏
    1)思路:

① 这道题是典型的贪心算法通过局部最优解得到全局最优解
② 我们的目标是到达数组的最后一个位置,因此我们可以考虑最后一步跳跃前所在的位置,该位置通过跳跃能够到达最后一个位置。
③ 如果有多个位置通过跳跃都能够到达最后一个位置,那么我们应该如何进行选择呢?直观上来看,我们可以 「贪心」地选择距离最后一个位置最远的那个位置,也就是对应下标最小的那个位置。因此,我们可以从左到右遍历数组,选择第一个满足要求的位置。
④ 找到最后一步跳跃前所在的位置之后,我们继续贪心地寻找倒数第二步跳跃前所在的位置,以此类推,直到找到数组的开始位置。
⑤ 所以记录一个要到达的索引位置 position ,最开始的索引值是 数组长度 - 1 ,每次贪心查找(从左到右遍历数组),如果找到前一个最远跳跃的点,就将该位置置为遍历到的索引。
⑥ 【具体:下标索引+值 >=索引位置,然后更新position位置,i重新开始】

2)代码:

class Solution {
    // 最小跳跃次数
    public int jump(int[] nums) {
        // 跳的步数
        int steps = 0;
        // 目标索引位置,只要新找到就会进行更新,知道来到起始位置0
        int position = nums.length-1;
        while(position > 0) {
            // 从前往后开始遍历,因为要确保索引最小,这样就可以使得跳跃次数最小
            // 最远只需要到position位置就行,后面的说明已经有保障
            for (int i = 0; i < position; i++) {
                if(i+nums[i] >= position) {
                    // 此时就说明一步可以到达
                    steps++;
                    // 然后进行更新position位置
                    position = i;
                    // i需要从0下标重新开始
                    break;
                }
            }
        }
        return steps;
    }
}

  1. 寻找重复数
    1)思路:

① 将这个题目给的特殊的数组当作一个链表来看,数组的下标就是指向元素的指针,把数组的元素也看作针。如 0是指针,指向 nums[0] ,而 nums[0] 也是指针,指向 nums[nums[0]]。
8
② 这样就转变为环形链表的问题:而要找到环形链表的入口,采用快慢双指针即可实现:
A. 定义快慢两个指针 slow 、 fast ,开始都是 0 表示在链表头部。
B. 一直循环,让慢指针走一步,即 slow=nums[slow] ;让快指针走两步,即 fast=nums[fast] 执行两次,也即
fast=nums[nums[fast]] 。[快指针两步,慢指针一步]
C. 再使用一个指针 finder ,最开始为 0 表示在链表头部;随后,它和 slow 每次向后移动一个位置。最终,它
们会在入环点相遇。
③ 格外注意下一个元素的位置,相当于是链表!!

2)代码:

import java.util.HashMap;

class Solution {
    public int findDuplicate(int[] nums) {
        // 使用快慢指针,直到相等时就退出循环
        int slow = 0;
        int fast = 0;
        while(true) {
            slow = nums[slow]; // 一步
            fast = nums[nums[fast]]; // 两步
            if(fast == slow) {
                break; // 退出循环
            }
        }
        // 定义第三个指针finder,用来找环形链表的入口!!
        int finder = 0;
        // 一直循环,直到与slow相遇(同时走)
        while(true) {
            finder = nums[finder];
            slow = nums[slow];
            if(finder == slow) {
                break;
            }
        }
        // 此时就是环形的入口
        return finder;
    }
}

111

  • 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、付费专栏及课程。

余额充值