努力经营当下,直至未来明朗!
文章目录
- 一、选择
- 二、编程
- 1. 跳跃游戏[贪心算法]
- 2. 寻找重复数[注意思路!]
- 答案
- 1. 选择
- 2. 编程
普通小孩也要热爱生活!
一、选择
- HASH 函数冲突处理方式不包括以下哪一项:()
A. 开放定址法
B. 链地址法
C. 插入排序法
D. 公共溢出区法
- HashMap的数据结构是怎样的?()
A. 数组
B. 链表
C. 数组+链表
D. 二叉树
- 以下程序的运行结果是( )
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]
- 散列函数有共同的性质,则函数值应当以( )概率取其值域的每一个值。( )
A. 最大
B. 最小
C. 平均
D. 同等
二、编程
1. 跳跃游戏[贪心算法]
LeetCode45.跳跃游戏II
给你一个非负整数数组 nums ,你最初位于数组的第一个位置(也就是0下标)。数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。假设你总是可以到达数组的最后一个位置。
2. 寻找重复数[注意思路!]
LeetCode287.寻找重复数
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的
整数。
假设 nums 只有 一个重复的整数 ,找出 这个重复的数 。你设计的解决方案必须不修改数组 nums 且只用常量级 O(1) 的额外空间。
答案
1. 选择
- ① 插入排序是一种排序算法。
② Hash函数冲突的处理方法有:开放地址法,链地址法,再哈希法, 建立公共溢出区。
③ hash冲突的避免:设计哈希函数(直接定制法、除留余数法、平方取中法、折叠法、随机数法、数字分析法)、调节负载因子。
④ 解决 hash冲突:闭散列(开放定址法:线性探测、二次探测)、开散列/哈希通过(链地址法、开链法)、公共溢出区法。
【一定要区分“避免”和“解决”!!】
参考:Hash函数
故:选C
- ① HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对。
② 数组的每一个元素上可以挂key值相同的链表元素,链表主要为了解决哈希冲突而存在的。
故:选C
- 【最难理解的就是:
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
- ① Hash函数的算法运算所取得的值应当尽可能均匀的分布,否则就会出现哈希冲突。
② 哈希冲突可以减少,但是是无法避免的。
故:选D:同等概率
2. 编程
- 跳跃游戏
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)思路:
① 将这个题目给的特殊的数组当作一个链表来看,数组的下标就是指向元素的指针,把数组的元素也看作针。如 0是指针,指向 nums[0] ,而 nums[0] 也是指针,指向 nums[nums[0]]。
② 这样就转变为环形链表的问题:而要找到环形链表的入口,采用快慢双指针即可实现:
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;
}
}