哈希
哈希入门
LeetCode 1. 两数之和
注意添加顺序,先判断再添加...
class Solution { public int[] twoSum(int[] nums, int target) { //{nums value:index} Map<Integer,Integer> map = new HashMap<>(); List<Integer> res = new ArrayList<>(); for(int i = 0 ; i < nums.length ; i++){ if(map.containsKey(target-nums[i])){ res.add(i); res.add(map.get(target-nums[i])); break; } map.put(nums[i],i); } return res.stream().mapToInt(Integer::valueOf).toArray(); } }
给定整数数组 nums ,要求返回新的数组 counts , counts[i] 为当前位置到数组末尾比自己更小元素个数。
input
第一行是数组长度 N
一个长度 N 的整型数组
1<= nums.length <= 105,40 <=nums[i] <= 110
counts.length=nums.length
output
counts 数组
输入
5 81 82 76 75 100
输出
2 2 1 0 0
最容易想到的是暴力检索(O(n)),但是 1<=n<=10^5 那最多只能使用O(nlogn)的算法去求解
从后往前遍历,使用哈希表存储出现过元素值及其出现次数,先判断map中是否存在比当前元素小的值,有则更新次数,并将当前元素put进map
package com.coedes.datastruct.hash.huawei2022101202; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; /** * @description:from https://codefun2000.com/p/P1217 * @author: wenLiu * @create: 2024/4/20 20:07 */ public class Main { public static void main(String[] args) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); int N = Integer.parseInt(reader.readLine()); String[] strOfNums = reader.readLine().split(" "); int[] nums = new int[N]; for (int i = 0; i < strOfNums.length; i++) { nums[i] = Integer.parseInt(strOfNums[i]); } HashMap<Integer, Integer> map = new HashMap<>(); int[] res = new int[N]; int cnt; for (int i = N - 1; i >= 0; i--) { cnt = 0; for (int j = 40; j < nums[i]; j++) { if (map.size() == 0) { break; } if (map.containsKey(j)) { cnt += map.get(j); } } res[i] = cnt; map.merge(nums[i], 1, Integer::sum); } for (int i : res) { System.out.print(i + " "); } } }
LeetCode 2653. 滑动子数组的美丽值
先尝试了 固定滑动窗口+排序 结果超时了 时间复杂度应该是O(nlogn)吧....
package com.coedes.datastruct.hash.likou2653; import java.util.ArrayList; import java.util.Collections; /** * @description:https://leetcode.cn/problems/sliding-subarray-beauty/description/ * @author: wenLiu * @create: 2024/4/20 20:56 */ public class Solution { public static void main(String[] args) { // nums = [1,-1,-3,-2,3], k = 3, x = 2 int[] nums = {-3, 1, 2, -3, 0, -3}; int k = 2; int x = 1; int[] ints = new Solution().getSubarrayBeauty(nums, k, x); for (int i : ints) { System.out.print(i + " "); } } public int[] getSubarrayBeauty(int[] nums, int k, int x) { int n = nums.length; int[] res = new int[n - k + 1]; ArrayList<Integer> list = new ArrayList<>(); int indexOfRes = 0; for (int r = 0, l = 0; r < n; r++) { list.add(nums[r]); while (r - l + 1 > k) { // list.remove(l); list.remove(0); l++; } if (list.size() == k) { System.out.println(list.toString()); ArrayList<Integer> tmpList = new ArrayList<>(list); Collections.sort(tmpList); //如果子数组中第 x 小整数 是 负数 ,那么美丽值为第 x 小的数,否则美丽值为 0 。 res[indexOfRes++] = tmpList.get(x - 1) < 0 ? tmpList.get(x - 1) : 0; } } return res; } }
class Solution { public int[] getSubarrayBeauty(int[] nums, int k, int x) { final int BIAS = 50; var cnt = new int[BIAS * 2 + 1]; int n = nums.length; for (int i = 0; i < k - 1; ++i) // 先往窗口内添加 k-1 个数 ++cnt[nums[i] + BIAS]; var ans = new int[n - k + 1]; for (int i = k - 1; i < n; ++i) { ++cnt[nums[i] + BIAS]; // 进入窗口(保证窗口有恰好 k 个数) int left = x; for (int j = 0; j < BIAS; ++j) { // 暴力枚举负数范围 [-50,-1] left -= cnt[j]; if (left <= 0) { // 找到美丽值 ans[i - k + 1] = j - BIAS; break; } } --cnt[nums[i - k + 1] + BIAS]; // 离开窗口 } return ans; } } 作者:灵茶山艾府 链接:https://leetcode.cn/problems/sliding-subarray-beauty/solutions/2241294/hua-dong-chuang-kou-bao-li-mei-ju-by-end-9mvl/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
20240410-华为实习-第一题
编写程序,根据给定的计费日志和计费单价列表,计算每个客户的总话单费用。对于重复上报的日志,只计费一次,选择先上报的日志。
1. 输入:
- 计费日志:包含时间戳、客户标识、计费因子、计费时长等字段。
- 计费因子的计费单价列表。
2. 要求:
- 对于同一客户同一计费因子在相同时间戳上报多次的情况,只计费一次(选择先上报的日志进行计费)。
- 计算每个客户的话单总费用,根据计费因子的单价列表计算费用。
输入描述
第1行表示计费日志的条数n,是一个正整数,范围是1≤n≤1000
第2到n+1行表示云服务的计费日志,
共4列,
第1列表示时间(是一个数字字符串,长度为10)、
第2列表示客户标识(是一个字符串,长度为 1~16 )、
第3列表示计费因子(是一个字符串,长度为 1~16 ,计费因子查不到时认为计费因子单价是0)、
第4列表示计费时长(范围为0~100,当计费时长不在范围内要认为是计费日志有问题,当成计费时长为0处理),
这4个字段使用逗号分隔,第n+2行表示计费因子的数量,m是一个正整数,范围是1≤m≤100。
第n+3到n+3+m行表示各种计费因子的计费单价的列表,该表有2列,第1列表示计费因子(是一个字符串,长度为 1~16 ),
第2列表示单价(是一个正整数,范围为 1~180),这2个字段使用逗号分隔。
输出描述
每个客户的话单总费用,共2列,第1列表示客户名,第2列表示话单费用,2列用逗号分割,输出按客户标识字典序升序排序。
样例1 输入 5 1627845600,client1,factorA,10 1627845605,client2,factorB,15 1627845610,client1,factorA,5 1627845615,client1,factorB,7 1627845620,client2,factorB,20 2 factorA,5 factorB,7 输出 client1,131 client2,245 说明 client1= 15*5+8*7=131 client2= 0*5+35*7=245
思路:哈希+模拟
输入时,利用hashSet去重,key = 时间戳+客户标识+计费因子。同时用hashMap存储计费因子和单价映射 eg:{factorA:5}
处理过程,同样用map存储客户的话单总费用映射 eg : {client1:131}
输出,按客户标识字典序升序排序,stream流重写compartor方法。
没仔细测试...只是过了样例...
package com.coedes.datastruct.hash.huawei2024042301; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.TreeMap; /** * @description:https://i.cnblogs.com/posts/edit;postId=18148079 * @author: wenLiu * @create: 2024/4/23 13:43 */ public class Main { public static void main(String[] args) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(reader.readLine()); HashSet<String> set = new HashSet<>();//去重 HashSet<String[]> logs = new HashSet<>();// 去重后的log for (int i = 0; i < n; i++) { String[] split = reader.readLine().split(","); //1627845600,client1,factorA,10 String key = split[0] + split[1] + split[2]; if (!set.contains(key)) { set.add(key); logs.add(split); } } int m = Integer.parseInt(reader.readLine()); HashMap<String, Integer> factor2Price = new HashMap<>();//计费因子:单价 映射集 for (int i = 0; i < m; i++) { String[] split = reader.readLine().split(","); factor2Price.put(split[0],Integer.parseInt(split[1])); } Map<String, Long> res = new TreeMap<>(); for (String[] log : logs) { //1627845600,client1,factorA,10 String client = log[1]; int price = factor2Price.get(log[2]); long sum = price*Integer.parseInt(log[3]); res.put(client,res.getOrDefault(client,0L)+sum); } for (Map.Entry<String, Long> entry : res.entrySet()) { System.out.println(entry.getKey() + "," + entry.getValue()); } } }
携程2024031301
给定一个字符串,重排这个字符串,使其包含尽可能多的“you”连续子串。
输入描述
一个仅包含小写字母的字符串,长度不超过 105。
输出描述
重排后的字符串,多解时任意输出。
样例
输入
yyoouuuu
输出
youyouuu
思路
使用了 HashMap
数据结构来统计字符串中每个字符的个数。具体做法是:
- 使用
HashMap<Character, Integer>
统计字符串中每个字符(y, o, u)的个数。 - 计算能够组成的“you”的最大数量。
- 使用
StringBuilder
构造包含尽可能多“you”子串的结果字符串。 - 将剩余的字符按照原来的顺序追加到结果字符串的后面。
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; /** * @author 17259 * @create 2024-07-06 10:09 */ public class Main { public static String rearrangeString(String s) { // 统计字符串中每个字符的个数 Map<Character, Integer> count = new HashMap<>(); for (char c : s.toCharArray()) { count.put(c, count.getOrDefault(c, 0) + 1); } // 计算可以组成的 "you" 的最大数量 int maxYous = Math.min(count.getOrDefault('y', 0), Math.min(count.getOrDefault('o', 0), count.getOrDefault('u', 0))); // 构造包含最多 "you" 的结果字符串 StringBuilder result = new StringBuilder(); for (int i = 0; i < maxYous; i++) { result.append("you"); } // 减去已经使用掉的字符 count.put('y', count.getOrDefault('y', 0) - maxYous); count.put('o', count.getOrDefault('o', 0) - maxYous); count.put('u', count.getOrDefault('u', 0) - maxYous); // 将剩余的字符添加到结果字符串后面 for (Map.Entry<Character, Integer> entry : count.entrySet()) { for (int i = 0; i < entry.getValue(); i++) { result.append(entry.getKey()); } } return result.toString(); } public static void main(String[] args) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String s = reader.readLine(); System.out.println(rearrangeString(s)); } }