哈希

哈希入门

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 数据结构来统计字符串中每个字符的个数。具体做法是:

  1. 使用 HashMap<Character, Integer> 统计字符串中每个字符(y, o, u)的个数。
  2. 计算能够组成的“you”的最大数量。
  3. 使用 StringBuilder 构造包含尽可能多“you”子串的结果字符串。
  4. 将剩余的字符按照原来的顺序追加到结果字符串的后面。
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));
    }
}

  

 

 

 

  

posted @ 2024-04-20 22:53  菠萝包与冰美式  阅读(5)  评论(0编辑  收藏  举报