7月算法训练------第七天(哈希表)解题报告
题目类型:哈希表
题目难度:简单
第一题、970. 强整数
- 题目链接:970. 强整数
- 思路分析:
-
暴力法1:
我们用两个ArrayList hsx
和hsy
模拟哈希表,实现不能添加重复元素。
其中hsx
用来存储x
的i
次幂;hsy
用来存储y
的j
次幂。
我们声明一个ArrayList hs
,用来存储最终结果。
然后我们遍历hsx
和hsy
,如果他们的和小于bound
,且hs中不含hsx.get(i) + hsy.get(j)
,则将hsx.get(i)
和hsy.get(j)
的和存入hs
中,最后返回hs
。这里我们使用
ArrayList
中的contians(Object o)
来类似哈希表中不出现重复值。
- 代码:
class Solution {
public List<Integer> powerfulIntegers(int x, int y, int bound) {
// List<Integer> list = new ArrayList();
List<Integer> hsx = new ArrayList();
List<Integer> hsy = new ArrayList();
List<Integer> hs = new ArrayList();
if(x == 1){
hsx.add(1);
}else{
for(int i = 0; (int)Math.pow(x, i) < bound; i++){
if(!hsx.contains((int)Math.pow(x, i)))
hsx.add((int)Math.pow(x, i));
}
}
if(y == 1){
hsy.add(1);
}else{
for(int j = 0; (int)Math.pow(y, j) < bound; j++){
if(!hsy.contains((int)Math.pow(y, j)))
hsy.add((int)Math.pow(y, j));
}
}
for(int i = 0; i < hsx.size(); i++){
for(int j = 0; j < hsy.size(); j++){
if(hsx.get(i) + hsy.get(j) <= bound){
if(!hs.contains(hsx.get(i) + hsy.get(j)))
hs.add(hsx.get(i) + hsy.get(j));
}
}
}
return hs;
}
}
- 暴力法2:
- 如果 x i > b o u n d x^i > bound xi>bound,那么 x i + y j x^i + y^j xi+yj也不可能小于等于 b o u n d bound bound。 对于 y j y^j yj也是同样的道理。
因此,我们只需要对于所有的 0 ≤ i , j ≤ log x ( bound ) < 20 0 \leq i, j \leq \log_x(\text{bound})< 20 0≤i,j≤logx(bound)<20 生成一遍答案就行了。
我们可以用一个 HashSet 来存储所有不同的答案。
代码:
class Solution {
public List<Integer> powerfulIntegers(int x, int y, int bound) {
Set<Integer> seen = new HashSet();
for (int i = 0; i < 20 && Math.pow(x, i) <= bound; ++i)
for (int j = 0; j < 20 && Math.pow(y, j) <= bound; ++j) {
int v = (int) Math.pow(x, i) + (int) Math.pow(y, j);
if (v <= bound)
seen.add(v);
}
return new ArrayList(seen);
}
}
第二题、914. 卡牌分组
- 题目链接:914. 卡牌分组
- 思路分析:
我们用一个HashMap hm
来存储deck
中的数和出现次数,key
为deck
中的数,对应的value
为该key
值在deck
中出现的次数;
比如:deck=[1,2,3,4,4,3,2,1]
那么:hm={key=1, value=2; key=2, value=2; key=3, value=2; key=4, value=2}
;
然后我们将value
用一个数组存起来,求出最小的value
值;
我们将X
从2
开始迭代,直到最小value
值;如果其他value
值与该j
值的余数不为0
,则用布尔数组记录该次迭代为false
,说明我们当前的迭代值不满足题意;如果余数全为0
,则说明能找到X
值满足题意;
当我们再次遍历这个布尔数组,只要有true
,就返回true
;如果全为false
就返回false
; - 代码:
class Solution {
public boolean hasGroupsSizeX(int[] deck) {
if(deck.length < 2){
return false;
}
Map<Integer, Integer> hm = new HashMap();
for(int i = 0; i < deck.length; i++){
if(hm.containsKey(deck[i])){
hm.replace(deck[i], hm.get(deck[i]), hm.get(deck[i]) + 1);
}else{
hm.put(deck[i], 1);
}
}
int[] count = new int[hm.size()];
int j = 0;
for(int i : hm.keySet()){
count[j] = hm.get(i);
j++;
}
Arrays.sort(count);
int x = count[0];
j = 2;
if(x < 2) {
return false;
}
boolean[] br = new boolean[x - 1];
for(; j <= x; j++){
for(int i = 0; i < count.length; i++){
if(count[i] % j != 0){
br[j-2] = false;
break;
}else{
br[j-2] = true;
}
}
}
for(int i = 0; i < br.length; i++){
if(br[i]){
return true;
}
}
return false;
}
}
第三题、1497. 检查数组对是否可以被 k 整除
-
思路分析:
我们对每个数取模,,放进一个长度为k
的数组mod
中,对负数,我们按照以下规则取模:
((arr[i] % k) + k) % k
这个结果就是mod
的下标。
我们分析,对于正数,以上规则与取一次模的结果其实是一样的的,所以正数也按以上规则取模。
当取模结果为0时,说明这个数本身就能被k整除,那么我们需要找一个也能被0整除的数来与其配对,所以mod[0]要为偶数;
对于取模不为0
的,取模结果为i
的要与取模结果为k-i
的数量要想等,这样才能返回true
。 -
代码:
class Solution {
public boolean canArrange(int[] arr, int k) {
int[] mod = new int[k];
for(int i = 0; i < arr.length; i++){
mod[((arr[i] % k) + k) % k]++;
}
for(int i = 1; i < k; i++){
if(mod[i] != mod[k - i]){
return false;
}
}
return mod[0] % 2 == 0;
}
}
第四题、面试题 17.05. 字母与数字
- 题目链接:面试题 17.05. 字母与数字
- 思路分析:
[“A”,“1”,“B”,“C”,“D”,“2”,“3”,“4”,“E”,“5”,“F”,“G”,“6”,“7”,“H”,“I”,“J”,“K”,“L”,“M”]
先申请一个长度为array.length的数组memo,如果遇到数字将memo[i]赋值为-1,如果遇到字母则将memo[i]赋值为1;
即:[1,-1,1,1,1,-1,-1,-1,1,-1,1,1,-1,-1,1,1,1,1,1,1]
然后将其计算和:
[1, 0, 1, 2, 3, 2, 1, 0, 1, 0, 1, 2, 1, 0, 1, 2, 3, 4, 5, 6]
指定左右两个指针,分别从左右两边遍历数组,找到最远的两个1,返回这最远两个1之间的子序列。 - 代码:
class Solution {
public String[] findLongestSubarray(String[] array) {
int len = array.length;
int[] memo = new int[(len << 1) + 1];
Arrays.fill(memo, -2);
memo[len] = -1;
int res = 0, count = 0, begin = 0, end = 0;
for (int i = 0; i < len; ++i) {
boolean is_num = true;
for (char c : array[i].toCharArray())
if (c < '0' || c > '9') {
is_num = false;
break;
}
count += is_num ? -1 : 1;
if (memo[count + len] <= -2)
memo[count + len] = i;
else if (i - memo[count + len] > res) {
begin = memo[count + len] + 1;
end = i + 1;
res = i - memo[count + len];
}
}
return Arrays.copyOfRange(array, begin, end);
}
}