链接:LeetCode
[Leetcode]5894. 至少在两个数组中出现的值
给你三个整数数组 nums1、nums2 和 nums3 ,请你构造并返回一个 不同 数组,且由 至少 在 两个 数组中出现的所有值组成。数组中的元素可以按 任意 顺序排列。
遍历即可。
class Solution
{
public List<Integer> twoOutOfThree(int[] nums1, int[] nums2, int[] nums3)
{
Set<Integer> us1 = new HashSet<>();
for (int x: nums1) us1.add(x);
Set<Integer> us2 = new HashSet<>();
for (int x : nums2) us2.add(x);
Set<Integer> us3 = new HashSet<>();
for (int x : nums3) us3.add(x);
Set<Integer> us = new HashSet<>();
us.addAll(us1);
us.addAll(us2);
us.addAll(us3);
List<Integer> res = new ArrayList<>();
for (int x : us)
{
int f1 = us1.contains(x) == true ? 1 : 0;
int f2 = us2.contains(x) == true ? 1 : 0;
int f3 = us3.contains(x) == true ? 1 : 0;
if (f1 + f2 + f3 >= 2)
{
res.add(x);
}
}
return res;
}
}
[Leetcode]5895. 获取单值网格的最小操作数
给你一个大小为 m x n 的二维整数网格 grid 和一个整数 x 。每一次操作,你可以对 grid 中的任一元素 加 x 或 减 x 。
单值网格 是全部元素都相等的网格。
返回使网格化为单值网格所需的 最小 操作数。如果不能,返回 -1 。
贪心。要使任意两元素最终相等,这两元素的差必须是 x 的倍数,否则无法通过加减 x 来相等。我们可以以数组中的某一元素为基准,若所有元素与它的差均为 x 的倍数,则任意两元素之差为 x 的倍数。
假设要让所有元素均为 y,设小于 y 的元素有 p 个,大于 y 的元素有 q 个,可以发现:
若 p<q,y 每增加 x,操作数就可以减小 q-p;
若 p>q,y 每减小 x,操作数就可以减小 p-q;
因此 p=q 时可以让总操作数最小,此时 yy 为所有元素的中位数。
class Solution {
public int minOperations(int[][] grid, int x) {
List<Integer> nums = new ArrayList<>();
int n = grid.length, m=grid[0].length;
for(int i=0;i<n;++i) {
for(int j=0;j<m;++j) {
nums.add(grid[i][j]);
}
}
//Collections.sort(nums);
nums.sort(Comparator.naturalOrder());
var ind = (m*n-1)/2;
int val = nums.get(ind);
int res = 0;
for(var num:nums) {
int result = Math.abs(num-val) / x;
if((num-val)%x == 0) res += result;
else return -1;
}
return res;
}
}
[Leetcode]5896. 股票价格波动
给你一支股票价格的数据流。数据流中每一条记录包含一个 时间戳 和该时间点股票对应的 价格 。
不巧的是,由于股票市场内在的波动性,股票价格记录可能不是按时间顺序到来的。某些情况下,有的记录可能是错的。如果两个有相同时间戳的记录出现在数据流中,前一条记录视为错误记录,后出现的记录 更正 前一条错误的记录。
请你设计一个算法,实现:
更新 股票在某一时间戳的股票价格,如果有之前同一时间戳的价格,这一操作将 更正 之前的错误价格。
找到当前记录里 最新股票价格 。最新股票价格 定义为时间戳最晚的股票价格。
找到当前记录里股票的 最高价格 。
找到当前记录里股票的 最低价格 。
请你实现 StockPrice 类:
StockPrice() 初始化对象,当前无股票价格记录。
void update(int timestamp, int price) 在时间点 timestamp 更新股票价格为 price 。
int current() 返回股票 最新价格 。
int maximum() 返回股票 最高价格 。
int minimum() 返回股票 最低价格 。
int current() 返回股票 最新价格。我们只需要维护两个变量,最大的时间戳以及对应的价格即可
而对于其他方法,我们需要读取的是股票的最低以及最高价格,但是update方法会更正某些时间戳的价格,因此股票的最高和最低价格是动态更新的。使用一个treemap,维护价格和时间戳的对应关系,对于某个价格,该股票可能有多个对应的时间戳,利用treemap的特性我们可以在o(1)的时间复杂度内获取当前最大和最小价格。我们可以使用map维护每个时间戳对应的价格。
而update方法就需要维护上面的两个map。通过map,我们可以得到需要更新的时间戳原价是多少,再通过这个价格,定位到treemap里面,删除该时间戳。然后再将该时间戳和价格的对应关系插入到map和treemap里面。
class StockPrice {
//timeStamp ->price
Map<Integer, Integer> map = new HashMap<>();
//price -> timeStamps
TreeMap<Integer, Set<Integer>> up = new TreeMap<>();
int curTime=-1,curPrice=-1;
public StockPrice() {
}
public void update(int timestamp, int price) {
if (timestamp>=curTime)
{
curTime=timestamp;
curPrice=price;
}
if(map.containsKey(timestamp)){
Integer old = map.get(timestamp);
up.get(old).remove(timestamp);
if (up.get(old).isEmpty())
up.remove(old);
}
map.put(timestamp, price);
if (!up.containsKey(price))
up.put(price,new HashSet<>());
up.get(price).add(timestamp);
}
public int current() {
return curPrice;
}
public int maximum() {
return up.lastKey();
}
public int minimum() {
return up.firstKey();
}
}
/**
* Your StockPrice object will be instantiated and called as such:
* StockPrice obj = new StockPrice();
* obj.update(timestamp,price);
* int param_2 = obj.current();
* int param_3 = obj.maximum();
* int param_4 = obj.minimum();
*/
[Leetcode]5897. 将数组分成两个数组并最小化数组和的差
给你一个长度为 2 * n 的整数数组。你需要将 nums 分成 两个 长度为 n 的数组,分别求出两个数组的和,并 最小化 两个数组和之 差的绝对值 。nums 中每个元素都需要放入两个数组之一。
请你返回 最小 的数组和之差。
将 2n 个数组拆分成左右两个数组(前n个,后n个), 然后分别求出这两个数组的所有组合情况,最后遍历组合情况找到最佳结果
不拆的话组合情况数太多,因此拆成两个数组分别求组合情况。
class Solution {
public int minimumDifference(int[] nums) {
// 前 n 个元素元素组合情况存储在left 中, 后 n 个元素组合请情况存储在 right 中
// Map<元素个数, Set<key个元素的总和>>
Map<Integer, TreeSet<Integer>> left = new HashMap<>();
Map<Integer, TreeSet<Integer>> right = new HashMap<>();
int min = Integer.MAX_VALUE;
int total = 0;
int n = nums.length / 2;
for(int i=0;i < 2 * n;i++){
total += nums[i];
if(i < n){
left.put(i+1, new TreeSet<>());
}else{
right.put(i - n + 1, new TreeSet<>());
}
}
dfs(nums, 0, 0, 0, n, left);
dfs(nums, 0, 0, n, 2*n, right);
// 情况一, 一部分元素在左侧,一部分元素在右侧
for(int i=1;i<n;i++){
TreeSet<Integer> set = left.get(i);
for(int leftSum : set){
// 前 i 个元素在 left 中, 后 n - i 个元素在 right 中
// 最佳情况是分成两侧相等即 total / 2, 寻找最佳组合最近的组合
Integer rightSum = right.get(n-i).ceiling(total / 2 - leftSum);
if(null != rightSum){
int sum = leftSum + rightSum;
min = Math.min(min, Math.abs(sum - (total - sum)));
}
rightSum = right.get(n-i).floor(total / 2 - leftSum);
if(null != rightSum){
int sum = leftSum + rightSum;
min = Math.min(min, Math.abs(sum - (total - sum)));
}
if(min == 0){
return 0;
}
}
}
// 情况二, 所有元素都来源与一侧
TreeSet<Integer> set = left.get(n);
for(int sum : set){
min = Math.min(min, Math.abs(sum - (total - sum)));
}
return min;
}
/**
* 递归枚举所有的元素组合,将元素组合情况存 Map<元素个数, Set<key个元素的总和>> 中
*
* @param nums
* @param sum 已选数组和
* @param count 已选数个数
* @param idx 当前索引
* @param limit 索引边界
* @param visited
*/
public void dfs(int[] nums, int sum, int count, int idx, int limit, Map<Integer, TreeSet<Integer>> visited){
if(visited.containsKey(count)){
visited.get(count).add(sum);
}
if(idx >= limit) return ;
// 选择当前元素
dfs(nums, sum + nums[idx], count+1, idx+1, limit, visited);
// 不选当前元素
dfs(nums, sum, count, idx+1, limit, visited);
}
}