【第一题】独一无二的出现次数
分析:
方法1:构建哈希表<Integer,Integer>,表示出现次数与元素的映射。将出现次数假如集合,假如有相同的元素在集合中,就会添加失败
public boolean uniqueOccurence(int[] arr){
Map<Integer,Integer> map = new HashMap<>();
for(int i = 0;i < arr.length;i++){
map.put(arr[i],map.getOrDefault(arr[i],0)+1);
}
Set<Integer> set = new HashSet<>();
for(int value:map.values()){
if(!set.add(value))
return false;
}
return true;
}
方法2:记录value,然后将value改为0,再去看map中有没有匹配的。
//执行用时:2 ms, 在所有 Java 提交中击败了87.80% 的用户
//内存消耗:36.4 MB, 在所有 Java 提交中击败了54.51% 的用户
class Solution {
public boolean uniqueOccurrences(int[] arr) {
HashMap<Integer,Integer> map = new HashMap<>();
for(int i = 0;i < arr.length;i++){
map.put(arr[i],map.getOrDefault(arr[i],0)+1);
}
for(int i : map.keySet()){
int tmp = map.get(i);
map.put(i,0);
//System.out.println(map);
//System.out.println(tmp);
if(map.containsValue(tmp)){
return false;
}
}
return true ;
}
}
【第二题】存在重复元素
分析:
方法一:直接用HashSet判重。
方法二:哈希映射
//执行用时:8 ms, 在所有 Java 提交中击败了55.15% 的用户
//内存消耗:44.4 MB, 在所有 Java 提交中击败了46.24% 的用户
class Solution {
public boolean containsDuplicate(int[] nums) {
HashSet<Integer> set = new HashSet<Integer>();
for(int i = 0;i < nums.length;i++){
if(!set.contains(nums[i])){
set.add(nums[i]);
}else{
return true;
}
}
return false;
}
}
//____________________________________________________
//执行用时:5 ms, 在所有 Java 提交中击败了76.63% 的用户
//内存消耗:42.5 MB, 在所有 Java 提交中击败了78.03% 的用户
class Solution {
public boolean containsDuplicate(int[] nums) {
HashSet<Integer> set = new HashSet<Integer>();
for(int i = 0;i < nums.length;i++){
if(!set.add(nums[i])){
return true;
}
}
return false;
}
}
//哈希咋嫩个慢?
//执行用时:17 ms, 在所有 Java 提交中击败了6.24% 的用户
//内存消耗:44.1 MB, 在所有 Java 提交中击败了56.26% 的用户
class Solution{
public boolean containsDuplicate(int[] nums){
HashMap<Integer,Integer> map = new HashMap<>();
for(int i = 0;i < nums.length;i++){
map.put(nums[i],map.getOrDefault(nums[i],0)+1);
if(map.get(nums[i])>1){
return true;
}
}
return false;
}
}
【第三题】重复N次的元素
分析:跟上边那题没啥差别。
方法一:依然哈希集
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:39.3 MB, 在所有 Java 提交中击败了69.92% 的用户
class Solution {
public int repeatedNTimes(int[] A) {
HashSet<Integer> set = new HashSet<>();
for(int i = 0;i < A.length;i++){
if(!set.add(A[i])){
return A[i];
}
}
return 0;
}
}
【第四题】最长回文串
分析:遍历字符串;
假如字母出现次数>=2:
1.刚好为偶数,sum += count;
2.为奇数,sum=sum+count-1;
假如有字母只出现一次:
sum+=1;(回文串允许有一个不同的字母放在中间)
实现:首先构造哈希表,key为字符串中的字符,Value为字符出现的次数。
class Solution {
public int longestPalindrome(String s) {
int sum = 0;
int flag = 0;
HashSet<Character> set = new HashSet<>();
for(char c:s.toCharArray()){
set.add(c);
}
if(set.size() == 1){
return s.length();
}
HashMap<Character,Integer> map= new HashMap<>();
for(int i = 0;i < s.length();i++){
map.put(s.charAt(i),map.getOrDefault(s.charAt(i),0)+1);
}
for(char c:map.keySet()){
//假如是偶数,那么可以直接加入回文串
if(map.get(c) % 2 == 0){
sum+=map.get(c);
}else{
//假如数量大于2,可以将偶数部分加入回文串
if(map.get(c) > 2){
if(flag == 0){
sum=sum+map.get(c);
flag = 1;
}else{
sum=sum+map.get(c)-1;
}
}
if(map.get(c) == 1){
if(flag == 0){
sum +=1;
flag = 1;
}
}
}
}
return sum;
}
}
//执行用时:1 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:37 MB, 在所有 Java 提交中击败了31.31% 的用户
class Solution{
public int longestPalindrome(String s){
int[] cnt = new int[58];
for(char c:s.toCharArray()){
cnt[c - 'A']+=1;
}
int ans = 0;
for(int x:cnt){
//x&1判断奇偶
ans+=x-(x&1);
}
//只允许一个奇数次加入
return ans < s.length()? ans+1:ans;
}
}
【第五题】最长和谐子序列
分析:
方法一:首先建立哈希表,key为数组中的各个数字,value为各个数字出现的次数。
遍历哈希表的keySet,假如存在i+1的key,(也就是说刚好和当前的key相邻),那么把他们的出现次数相加,要是不存在,那说明和谐数组不包括他俩。
方法二:先将数组排序,然后根据元素大小设定一个窗口(由两个指针构成),窗口中的key之差不超过1.
//执行用时:19 ms, 在所有 Java 提交中击败了83.01% 的用户
//内存消耗:39.8 MB, 在所有 Java 提交中击败了43.34% 的用户
class Solution {
public int findLHS(int[] nums) {
int max = 0;
int count = 0;
if(nums.length == 0){return 0;}
HashMap<Integer,Integer> map = new HashMap<>();
for(int i = 0;i < nums.length;i++){
map.put(nums[i],map.getOrDefault(nums[i],0)+1);
}
for(Integer i:map.keySet()){
if(map.containsKey(i+1)){
count = map.get(i)+map.get(i+1);
}else{
count = 0;
}
max = Math.max(max,count);
}
return max;
}
}
//执行用时:16 ms, 在所有 Java 提交中击败了90.10% 的用户
//内存消耗:39 MB, 在所有 Java 提交中击败了97.87% 的用户
class Solution {
public int findLHS(int[] nums) {
Arrays.sort(nums);
int begin = 0,res = 0;
for(int end = 0;end < nums.length;end++){
while(nums[end] - nums[begin] > 1)
begin++;
if(nums[end] - nums[begin] == 1)
res = Math.max(res,end - begin + 1);
}
return res;
}
}
【第六题】有效的字母异位词
分析:
方法一:直接在同一个哈希表上操作,一个+,一个-。
方法二:两个哈希表,比较各个字母的个数。
class Solution {
public boolean isAnagram(String s, String t) {
if (s.length() != t.length()) {
return false;
}
Map<Character, Integer> table = new HashMap<Character, Integer>();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
table.put(ch, table.getOrDefault(ch, 0) + 1);
}
for (int i = 0; i < t.length(); i++) {
char ch = t.charAt(i);
table.put(ch, table.getOrDefault(ch, 0) - 1);
if (table.get(ch) < 0) {
return false;
}
}
return true;
}
}
【第七题】第一个只出现一次的字符
分析:先遍历一次存入哈希表,key为字符,value为字符出现的次数,然后再遍历一次查找该字符出现的次数,直接输出次数为1的字符。
不行,不行!因为哈希表是无序的。还是得老老实实遍历数组。
//执行用时:35 ms, 在所有 Java 提交中击败了23.57% 的用户
//内存消耗:39 MB, 在所有 Java 提交中击败了56.53% 的用户
class Solution {
public char firstUniqChar(String s) {
//if(s.equals("")){return ' ';}
if(s.length() == 1){return s.charAt(0);}
Map<Character,Integer> map =new HashMap<>();
for(int i = 0;i < s.length();i++){
map.put(s.charAt(i),map.getOrDefault(s.charAt(i),0)+1);
}
for(int i = 0;i < s.length();i++){
if(map.get(s.charAt(i)) == 1){
return s.charAt(i);
}
}
return ' ';
}
}
优化:原本是统计每个字符的次数,现在将哈希表的value改成Boolean。
//执行用时:26 ms, 在所有 Java 提交中击败了59.88% 的用户
//内存消耗:38.8 MB, 在所有 Java 提交中击败了81.87% 的用户
class Solution{
public char firstUniqChar(String s){
HashMap<Character,Boolean> map = new HashMap<>();
char[] sc = s.toCharArray();
for(char c : sc){
map.put(c,!containsKey(c));
}
for(char c:sc){
if(map.get(c)){return c;}
}
return ' ';
}
}
【第八题】查找常用字符
分析:
方法一:数组迭代求交集;
方法二:给字符串中的每个字符建立一个哈希表,表示字符和出现次数的映射关系。求各个字符串的交集。
递归求交集。
//执行用时:8 ms, 在所有 Java 提交中击败了39.33% 的用户
//内存消耗:38.8 MB, 在所有 Java 提交中击败了25.72% 的用户
class Solution{
public List<String> commonChars(String[] A){
List<String> list = new ArrayList<>();
//res存放交集
int[] res = new int[26];
for(char c:A[0].toCharArray()){
res[c-'a']++;
}
for(int i = 1;i < A.length;i++){
int[] temp = new int[26];
for(char c:A[i].toCharArray()){
temp[c-'a']++;
}
for(int j = 0;j < 26;j++){
//这里取min好妙啊
res[j] = Math.min(res[j],temp[j]);
}
}
//将结果数组中的元素放入列表
for(int i = 0;i < res.length;i++){
if(res[i] > 0){
for(int j = 0;j < res[i];j++){
list.add((char)('a'+i)+"");
}
}
}
return list;
}
}
【第九题】员工的重要性(挖坑,搜索图的时候再做)
分析:主要有几步:1.找员工ID,记录重要度;2.找其下属;3.找下属ID;4.累加下属重要度。
确定数据结构:一对多(树?)
方法一:递归
【第十题】单词规律
分析:也就是说,str中的各个单词之间的规律是否符合pattern的规律。
方法一:直接替换呗,例如示例1,用a来代替str中的dog,用b来代替cat。
方法二:哈希表+哈希集
方法三:一个哈希表,利用了同一个位置的value,比较put的key是否相同。
方法四:一个哈希表,利用了"第n次put返回第n-1次的value"
//执行用时:1 ms, 在所有 Java 提交中击败了98.94% 的用户
//内存消耗:36.5 MB, 在所有 Java 提交中击败了66.37% 的用户
class Solution {
public boolean wordPattern(String pattern, String s) {
//将s按照空格分割成数组,个数不同返回false
String[] str = s.split(" ");
if(pattern.length() != str.length){
return false;
}
//哈希集去重:种类数目不同返回false
HashSet<Character> set1 = new HashSet<>();
HashSet<String> set2 = new HashSet<>();
for(int a = 0;a < pattern.length();a++){
set1.add(pattern.charAt(a));
set2.add(str[a]);
}
if(set1.size()!=set2.size()){
return false;
}
//哈希表:str中单词和pattern中的字符的映射
Map<Character,String> map = new HashMap<>();
//i指向pattern的每个字符,j指向s的每个单词
int i = 0,j = 0;
while(i < pattern.length() && j < str.length){
if(map.containsKey(pattern.charAt(i))){
if(!map.get(pattern.charAt(i)).equals(str[j])){
//System.out.println(pattern.charAt(i)+" "+map.get(pattern.charAt(i))+" "+str[j]);
return false;
}
}else{
map.put(pattern.charAt(i),str[j]);
}
i++;
j++;
}
return true;
}
}
//执行用时:1 ms, 在所有 Java 提交中击败了98.94% 的用户
//内存消耗:36.3 MB, 在所有 Java 提交中击败了91.16% 的用户
public boolean wordPattern(String pattern,String s){
String[] strings = s.split(" ");
if(pattern.length()!=strings.length){
return false;
}
HashMap<Object,Integer> hashMap = new HashMap<>();
for(int i = 0;i < pattern.length();i++){
//同一个value,比较两次放进去的key是否一样
if(!Objects.equals(hashMap.put(pattern.charAt(i),i),hashMap.put(strings[i],i))){
return false;
}
}
return true;
}
class Solution{
public boolean wordPattern(String pattern,String s){
String[] strs = s.split(" ");
if(pattern.length()!=strs.length){
return false;
}
Map map = new HashMap<>();
for(Integer i = 0;i < pattern.length();i++){
//利用map.put方法的返回值(key第一次put的时候返回null,第n次put则返回第n-1次的value)
if(map.put(pattern.charAt(i),i)!=map.put(strs[i],i)){
return false;
}
}
return true;
}
}
【第十一题】强整数
分析:哈希表标记。
//执行用时:1 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:36.2 MB, 在所有 Java 提交中击败了82.83% 的用户
class Solution {
public List<Integer> powerfulIntegers(int x, int y, int bound) {
/*
题目给定 x 与 y 都大于 0,因此不存在为 0 的情况
需要注意的点:
x 或 y 为 1 的时候,那么它的任何次幂都是 1 ,那么只需要计算一次即可
任何数的 0 次幂都是 1,因此计算时从 1 开始
*/
Set<Integer> set = new HashSet<>();
/*
使用 a 记录 x 的 n 次幂
使用 b 记录 y 的 n 次幂
外层循环结束条件 a < bound,即 x 的 n 次幂最多等于 bound - 1,因为 y 的 n 次幂最少为 1
内层循环结束条件 a + b <= bound,即 两数的幂之和超过 bound 时就退出
两个 break
若 y == 1,因为它的任何次幂都是 1,那么我们内层循环 a 只需要与 它 计算一次即可
若 x == 1 同理,只需要外层只需要计算一次即可,所有可能都在内层进行计算了
*/
for(int a = 1; a < bound; a *= x){
for(int b = 1; a + b <= bound; b *= y){
set.add(a + b);
if(y == 1) break;
}
if(x == 1) break;
}
return new ArrayList<>(set);
}
}
【第十一题】Bigram分词
分析:设置双指针.
//执行用时:1 ms, 在所有 Java 提交中击败了75.37% 的用户
//内存消耗:36.8 MB, 在所有 Java 提交中击败了56.62% 的用户
class Solution {
public String[] findOcurrences(String text, String first, String second) {
int i = 0,j = 1;
String[] str = text.split(" ");
List<String> con = new ArrayList<>();
while(j < str.length-1){
if(str[i].equals(first) && str[j].equals(second)){
con.add(str[j+1]);
i+=2;
j+=2;
}else{
i++;
j++;
}
}
return con.toArray(new String[con.size()]);
}
}
【第十二题】键盘行
分析:
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:36 MB, 在所有 Java 提交中击败了99.06% 的用户
class Solution {
public String[] findWords(String[] words) {
List<String> list = new ArrayList<>();
for(String word : words){
int first = getLine(word.charAt(0));
boolean flag = true;
for(int i = 1; i < word.length(); i++){
if(getLine(word.charAt(i)) != first){
flag = false;
break;
}
}
if(flag)
list.add(word);
}
return list.toArray(new String[list.size()]);
}
public int getLine(char c){
char ch = Character.toLowerCase(c);
if("qwertyuiop".indexOf(ch) != -1)
return 1;
else if("asdfghjkl".indexOf(ch) != -1)
return 2;
else
return 3;
}
}
【第十三题】存在重复元素II
分析:这里感觉题目有歧义,绝对值至多为k,那么假如出现多个值相等,他们的索引有的大于k有的小于k怎么算?
还是说所有可能的值,他们的索引差最多为k?
构建哈希表,key为数组中的值,value为每个值对应的索引
有点慢,但是想法还不错。
//执行用时:16 ms, 在所有 Java 提交中击败了32.37% 的用户
//内存消耗:47.2 MB, 在所有 Java 提交中击败了5.06% 的用户
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
Map<Integer,List<Integer>> map = new HashMap<>();
for(int i = 0;i < nums.length;i++){
if(map.containsKey(nums[i])){
int cha = Math.abs(i - map.get(nums[i]).get(0));
if(cha <= k){
return true;
}else{
map.get(nums[i]).set(0,i);
}
}else{
map.put(nums[i],new ArrayList<Integer>());
map.get(nums[i]).add(i);
}
}
return false;
}
}
上边可以优化,不用list,直接就和map.get(nums[i])比较即可。
同一个代码提交几次执行时间都不同…
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<>();
for(int i = 0;i < nums.length;i++){
if(map.containsKey(nums[i])){
int cha = Math.abs(i - map.get(nums[i]));
if(cha <= k){
return true;
}else{
map.put(nums[i],i);
}
}else{
map.put(nums[i],i);
}
}
return false;
}
}
【第十四题】子域名访问计数
分析:假如说[“900 google.mail.com”],其中google.mail.com肯定是访问了900次,mail.com访问的次数是包含这个域名的所有域名访问次数之和,.com也是包含这个域名的所有域名访问次数之和。
//执行用时:23 ms, 在所有 Java 提交中击败了63.67% 的用户
//内存消耗:39.5 MB, 在所有 Java 提交中击败了66.05% 的用户
class Solution {
public List<String> subdomainVisits(String[] cpdomains) {
Map<String,Integer> map = new HashMap<>();
for(String str:cpdomains){
String[] strings = str.split(" ");
int num = Integer.parseInt(strings[0]);
String[] sub = strings[1].split("\\.");
StringBuilder builder = new StringBuilder();
for(int i = sub.length -1;i >=0;i--){
if(builder.length() !=0){
builder.insert(0,".");
}
builder.insert(0,sub[i]);
String current = builder.toString();
int value = map.getOrDefault(current,0);
map.put(current,value+num);
}
}
return map.entrySet().stream().map(x->x.getValue() + " "+x.getKey()).collect(Collectors.toList());
}
}
【第十五题】分糖果
//执行用时:37 ms, 在所有 Java 提交中击败了84.14% 的用户
//内存消耗:40.4 MB, 在所有 Java 提交中击败了72.22% 的用户
class Solution {
public int distributeCandies(int[] candyType) {
int sum = candyType.length;
int count = 0;
HashSet<Integer> set = new HashSet<>();
for(int i :candyType){
set.add(i);
}
return Math.min(set.size(),sum/2);
}
}
【第十六题】同构字符串
分析:
和第十题单词规律有点像
方法一:哈希集去重+哈希表映射
方法二:哈希表映射,value判重
方法三:根据两次映射的
方法四:根据
//执行用时:15 ms, 在所有 Java 提交中击败了31.79% 的用户
//内存消耗:38.6 MB, 在所有 Java 提交中击败了53.61% 的用户
class Solution {
public boolean isIsomorphic(String s, String t) {
if(s.length()!=t.length()){return false;}
HashSet<Character> set1 = new HashSet<>();
HashSet<Character> set2 = new HashSet<>();
for(int i = 0;i < s.length();i++){
set1.add(s.charAt(i));
set2.add(t.charAt(i));
}
if(set1.size() != set2.size()){
return false;
}
Map<Character,Character> map = new HashMap<>();
for(int i = 0;i < s.length();i++){
if(!map.containsKey(s.charAt(i))){
map.put(s.charAt(i),t.charAt(i));
}else{
if(map.get(s.charAt(i))!=t.charAt(i)){
return false;
}
}
}
return true;
}
}
//执行用时:12 ms, 在所有 Java 提交中击败了57.32% 的用户
//内存消耗:38.5 MB, 在所有 Java 提交中击败了60.08% 的用户
class Solution {
public boolean isIsomorphic(String s, String t) {
if(s.length() != t.length()){
return false;
}
HashMap<Character, Character> map = new HashMap<>();
for(int i=0; i<s.length(); i++){
if(!map.containsKey(s.charAt(i))){
if(map.containsValue(t.charAt(i))){
return false;
}
map.put(s.charAt(i), t.charAt(i));
}else{
if(map.get(s.charAt(i))!=t.charAt(i)){
return false;
}
}
}
return true;
}
}
【第十七题】最短补全词
分析:将牌照中的字母提取,然后排序,和words中的每个单词(排好序)比较,设置两个指针,一个指向牌照中的字母(指针i),一个指向words中单词的字母(指针j),相等则双双往前,否则只有j往前,统计个数。
“1s3 PSt”
[“step”,“steps”,“stripe”,“stepple”]
“1s3 456”
[“looks”, “pest”, “stew”, “show”]
“Ah71752”
[“suggest”,“letter”,“of”,“husband”,“easy”,“education”,“drug”,“prevent”,“writer”,“old”]
“OgEu755”
[“enough”,“these”,“play”,“wide”,“wonder”,“box”,“arrive”,“money”,“tax”,“thus”]
//执行用时:4 ms, 在所有 Java 提交中击败了78.96% 的用户
//内存消耗:38.8 MB, 在所有 Java 提交中击败了83.22% 的用户
class Solution{
public String shortestCompletingWord(String licensePlate,String[] words){
int[] target = count(licensePlate);
String ans = "";
for(String word:words){
if((word.length()< ans.length()||ans.length()==0) && dominates(count(word.toLowerCase()),target))
ans = word;
return ans;
}
}
//比较两个数组里字母的值的大小
public boolean dominates(int[] count1,int[] count2){
for(int i = 0;i < 26;++i)
if(count1[i] < count2[i])
return false;
return true;
}
//不分大小写,将单词字母统计存入ans
public int[] count(String word){
int[] ans = new int[26];
for(char letter:word.toCharArray()){
int index = Character.toLowerCase(letter)-'a';
if(0 <=index && index < 26)
ans[index]++;
}
return ans;
}
}
【第十八题】设计哈希集合
分析:为了实现HashSet数据结构,有两个关键的问题,即哈希函数和冲突处理。
class MyHashSet{
private Bucket[] bucketArray;
private int keyRange;
public MyHashSet(){
this.keyRange = 769;
this.bucketArray = new Bucket[this.keyRange];
for(int i = 0;i < this.keyRange;++i)
this.bucketArray[i] = new Bucket();
}
protected int _hash(int key){
return (key % this.keyRange);
}
public void add(int key){
int bucketIndex = this._hash(key);
}
}