系列文章目录
目录
前言
本系列是个人力扣刷题汇总,本文是哈希表。刷题顺序按照[力扣刷题攻略] Re:从零开始的力扣刷题生活 - 力扣(LeetCode)
一、哈希表与统计
排序后,用两个指针,类似于窗口。没用哈希表
// 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 int findLHS(int[] nums) {
Arrays.sort(nums);
int begin =0;
int res=0;
for(int end=0;end<nums.length;end++){
if(nums[end]-nums[begin]>1){
begin++;
}
if(nums[end]-nums[begin]==1){
res = Math.max(res,end-begin+1);
}
}
return res;
}
}
用哈希表
class Solution {
public int findLHS(int[] nums) {
HashMap<Integer,Integer> cnt=new HashMap<>();
for(int num:nums){
cnt.put(num,cnt.getOrDefault(num,0)+1);
}
int res=0;
for(int key : cnt.keySet()){
if(cnt.containsKey(key+1)){
res=Math.max(res,cnt.get(key)+cnt.get(key+1));
}
}
return res;
}
}
辅助数组:通过使用一个辅助数组 map
来记录 nums1
数组中每个元素的出现次数,并根据 map
数组的信息,遍历 nums2
数组,找出两个数组的交集,并将交集存储在 nums2
数组中。
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
int[] map=new int[1001];
int count=0;
for(int num:nums1)
{
map[num]++;
}
for(int num:nums2)
{
if(map[num]>0)
{
nums2[count++]=num;
map[num]--;
}
}
return Arrays.copyOfRange(nums2,0,count);
}
}
哈希表:使用哈希表记录了 nums1
数组中每个元素及其出现次数,然后遍历 nums2
数组,根据哈希表的信息找到交集的元素,并将交集存储在 res
列表中。最后,将 res
列表转换为数组并返回。
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
Map<Integer,Integer> map = new HashMap<>();
List<Integer> res = new ArrayList<>();
for(int i : nums1){
if(!map.containsKey(i)) map.put(i,1);
else map.put(i,map.get(i)+1);
}
for(int i : nums2){
if(!map.containsKey(i)) continue;
else if(map.get(i) > 0){
map.put(i,map.get(i)-1);
res.add(i);
}
}
int[] array = new int[res.size()];
for (int i = 0; i < res.size(); i++) {
array[i] = res.get(i);
}
return array;
}
}
- 创建一个
HashMap
对象map
,用于记录每个断点位置出现的次数。 - 创建一个变量
max
,用于记录最大的断点次数。 - 定义方法
leastBricks
,接受一个二维列表wall
,表示砖墙的布局。方法返回穿过砖墙的最少砖块数。 - 遍历砖墙的每一行
row
,调用方法processRow
处理每一行的砖块布局。 - 返回砖墙的行数减去最大断点次数,即穿过砖墙的最少砖块数。
- 定义方法
processRow
,接受一个列表row
,表示砖墙的一行砖块布局。 - 初始化变量
rowSum
为第一个砖块的宽度,表示当前行的砖块边界位置。 - 遍历当前行的每个砖块,从第二个砖块开始。
- 获取
rowSum
在map
中对应的值f
,如果该值不存在,则默认为 0。 - 将
rowSum
在map
中的值加 1,并更新map
。 - 如果当前
f
值大于max
,则更新max
。 - 将
rowSum
累加当前砖块的宽度,得到下一个断点位置。
- 获取
- 方法执行完毕后,
map
中记录了所有断点位置出现的次数,max
记录了最大的断点次数。
遍历砖墙的每一行,记录每个断点位置出现的次数,最后返回穿过砖墙的最少砖块数。通过使用哈希表 map
记录断点位置的出现次数,可以有效计算最少砖块数。
class Solution{
private final Map<Integer, Integer> map = new HashMap<>();
private int max = 0;
public int leastBricks(List<List<Integer>> wall){
for (List<Integer> integers : wall){
processRow(integers);
}
return wall.size() - max;
}
public void processRow(List<Integer> row){
int rowSum = row.get(0);
for (int j = 1; j < row.size(); j++){
int f = map.getOrDefault(rowSum, 0) + 1;
map.put(rowSum, f);
if (f > max) max = f;
rowSum += row.get(j);
}
}
}
class Solution {
public List<List<String>> findDuplicate(String[] paths) {
HashMap<String, List<String>> contentToFileNames = new HashMap<>();//文件内容到文件全路径的映射
List<List<String>> res = new ArrayList<>();
for (String path : paths) {
char[] p = path.toCharArray();
int i = 0;
while (i < p.length && p[i] != ' ') {//路径名
i++;
}
String pathName = path.substring(0, i);
i++;
while (i < p.length) {
int j = i;
while (i < p.length && p[i] != '(') {//文件名
i++;
}
String fileName = path.substring(j, i);
i++;
j = i;
while (i < p.length && p[i] != ')') {//内容
i++;
}
String fileContent = path.substring(j, i);
//路径名+文件名可以唯一地确定一个文件
String fullPath = new StringBuilder(pathName).append("/").append(fileName).toString();
List<String> fileNameList = contentToFileNames.getOrDefault(fileContent, new ArrayList<>());
fileNameList.add(fullPath);
contentToFileNames.put(fileContent, fileNameList);
i += 2;
}
}
Set<String> keys = contentToFileNames.keySet();
for (String key : keys) {
List<String> fullPaths = contentToFileNames.get(key);
if (fullPaths.size() > 1) {
res.add(fullPaths);
}
}
return res;
}
}
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int[] max_min_1 = getMaxMin(nums1);
int[] max_min_2 = getMaxMin(nums2);
int[] max_min_3 = getMaxMin(nums3);
int[] max_min_4 = getMaxMin(nums4);
int res = 0;
int max = Math.max(max_min_1[1] + max_min_2[1], -(max_min_3[0]+max_min_4[0]));
int min = Math.min(max_min_1[0] + max_min_2[0], -(max_min_3[1]+max_min_4[1]));
int[] arr = new int[max-min+1];
for (int i : nums1) {
for (int j : nums2) {
arr[i+j -min]++;
}
}
for (int i : nums3) {
for (int j : nums4) {
res += arr[-(i+j)-min];
}
}
return res;
}
private int[] getMaxMin(int[] nums) {
int max = nums[0];
int min = nums[0];
for (int num : nums) {
if (max<num){
max = num;
}
if (min>num){
min = num;
}
}
return new int[]{min, max};
}
}
二、哈希表与前缀和
class Solution {
public int subarraySum(int[] nums, int k) {
//记录和为k的子数组的数量
int count = 0;
//前缀和
int preSum = 0;
//存储前缀和出现的次数
Map<Integer,Integer> map = new HashMap<>();
//特殊处理
map.put(0,1);
for (int i = 0; i < nums.length; i++) {
preSum += nums[i];
//满足条件的前缀和
if (map.containsKey(preSum - k)){
count += map.get(preSum - k);
}
//存储前缀和出现的次数
map.put(preSum,map.getOrDefault(preSum,0) + 1);
}
return count;
}
}
class Solution {
public boolean checkSubarraySum(int[] nums, int k) {
int n = nums.length;
int[] prefix = new int[n+1];
for (int i=1;i<n+1;i++) {
prefix[i] = nums[i-1]+prefix[i-1];
}
HashSet<Integer> set = new HashSet();
for (int i=2;i<=n;i++) {
set.add(prefix[i-2]%k);
if (set.contains(prefix[i]%k))
return true;
}
return false;
}
}
class Solution {
public int findMaxLength(int[] nums) {
if(nums.length == 0 || nums.length == 1)
return 0;
int maxLength = 0;
int[] arr = new int[2*nums.length+1];
for( int i = 0; i < arr.length; i++)
arr[i] = -2;
arr[nums.length]=-1;
int counter = nums.length;
for(int i = 0; i < nums.length; i++){
counter+=nums[i]*2-1;
if(arr[counter] == -2){
arr[counter] = i;
}else{
maxLength = Math.max(maxLength, i-arr[counter]);
}
}
return maxLength;
}
}
总结
待修改。。。