写点什么

2023-06-18:给定一个长度为 N 的一维数组 scores, 代表 0~N-1 号员工的初始得分, scores[i] = a, 表示 i 号员工一开始得分是 a, 给定一个长度为 M 的二维数组 operatio

  • 2023-06-18
    北京
  • 本文字数:5744 字

    阅读完需:约 19 分钟

2023-06-18:给定一个长度为 N 的一维数组 scores, 代表 0~N-1 号员工的初始得分,


scores[i] = a, 表示 i 号员工一开始得分是 a,


给定一个长度为 M 的二维数组 operations,


operations[i] = {a, b, c}。


表示第 i 号操作为 :


如果 a==1, 表示将目前分数<b 的所有员工,分数改成 b,c 这个值无用,


如果 a==2, 表示将编号为 b 的员工,分数改成 c,


所有操作从 0~M-1, 依次发生。


返回一个长度为 N 的一维数组 ans,表示所有操作做完之后,每个员工的得分是多少。


1 <= N <= 10 的 6 次方,


1 <= M <= 10 的 6 次方,


0 <= 分数 <= 10 的 9 次方。


来自 TikTok 美国笔试。


答案 2023-06-18:

具体步骤如下:

1.创建一个长度为 N 的一维数组scores,表示每个员工的初始得分。


2.创建一个长度为 M 的二维数组operations,表示操作序列。


3.定义一个函数operateScores2来处理操作序列。


4.初始化一个节点数组nodes,用于存储每个员工的节点信息。


5.初始化一个空的得分和桶的映射表scoreBucketMap


6.遍历scores数组,为每个得分值创建一个桶,并将对应的员工节点添加到桶中。


7.遍历operations数组,处理每个操作。


8.对于类型为 1 的操作,获取小于当前得分的最大得分值floorKeyV,然后将它们的桶合并到新的得分值对应的桶中。


9.对于类型为 2 的操作,获取该员工节点,并将其从原来的桶中移除,然后添加到新的得分值对应的桶中。


10.遍历得分和桶的映射表scoreBucketMap,将桶中的员工节点按照顺序取出,更新到结果数组ans中。


11.返回最终的结果数组ans


12.进行功能测试和性能测试。


时间复杂度分析:


  • 遍历scores数组并创建桶,时间复杂度为 O(N)。

  • 遍历operations数组,每个操作的时间复杂度为 O(logN)(由于使用了有序映射表来实现桶,检索操作的时间复杂度为 O(logN))。

  • 遍历得分和桶的映射表scoreBucketMap,每个桶中的员工节点数量为 O(1),遍历的时间复杂度为 O(N)。

  • 总体时间复杂度为 O(N + KlogN),其中 K 为操作序列的长度。


空间复杂度分析:


  • 创建一个长度为 N 的数组scores,空间复杂度为 O(N)。

  • 创建一个长度为 M 的数组operations,空间复杂度为 O(M)。

  • 创建一个长度为 N 的节点数组nodes,空间复杂度为 O(N)。

  • 创建一个有序映射表scoreBucketMap,储存每个得分值对应的桶,空间复杂度为 O(N)。

  • 结果数组ans的长度为 N,空间复杂度为 O(N)。

  • 总体空间复杂度为 O(N + M)。

go 完整代码如下:

package main
import ( "fmt" "math/rand" "time")
// 桶,得分在有序表里!桶只作为有序表里的value,不作为keytype Bucket struct { head *Node tail *Node}
func NewBucket() *Bucket { head := &Node{index: -1} tail := &Node{index: -1} head.next = tail tail.last = head return &Bucket{head: head, tail: tail}}
func (b *Bucket) add(node *Node) { node.last = b.tail.last node.next = b.tail b.tail.last.next = node b.tail.last = node}
func (b *Bucket) merge(join *Bucket) { if join.head.next != join.tail { b.tail.last.next = join.head.next join.head.next.last = b.tail.last join.tail.last.next = b.tail b.tail.last = join.tail.last join.head.next = join.tail join.tail.last = join.head }}
// Node represents a node in the buckettype Node struct { index int last *Node next *Node}
func (n *Node) connectLastNext() { n.last.next = n.next n.next.last = n.last}
// 暴力方法func operateScores1(scores []int, operations [][]int) []int { n := len(scores) ans := make([]int, n) copy(ans, scores)
for _, op := range operations { if op[0] == 1 { for i := 0; i < n; i++ { ans[i] = max(ans[i], op[1]) } } else { ans[op[1]] = op[2] } }
return ans}
// 正式方法func operateScores2(scores []int, operations [][]int) []int { n := len(scores) nodes := make([]*Node, n) scoreBucketMap := make(map[int]*Bucket)
for i := 0; i < n; i++ { nodes[i] = &Node{index: i} if _, ok := scoreBucketMap[scores[i]]; !ok { scoreBucketMap[scores[i]] = NewBucket() } scoreBucketMap[scores[i]].add(nodes[i]) }
for _, op := range operations { if op[0] == 1 { floorKeyV := floorKey(scoreBucketMap, op[1]-1)
if floorKeyV != -1 && scoreBucketMap[op[1]] == nil { scoreBucketMap[op[1]] = NewBucket() }
for floorKeyV != -1 { scoreBucketMap[op[1]].merge(scoreBucketMap[floorKeyV]) delete(scoreBucketMap, floorKeyV) floorKeyV = floorKey(scoreBucketMap, op[1]-1) } } else { cur := nodes[op[1]] cur.connectLastNext()
if scoreBucketMap[op[2]] == nil { scoreBucketMap[op[2]] = NewBucket() }
scoreBucketMap[op[2]].add(cur) } }
ans := make([]int, n) for score, bucket := range scoreBucketMap { cur := bucket.head.next for cur != bucket.tail { ans[cur.index] = score cur = cur.next } }
return ans}
func floorKey(m map[int]*Bucket, target int) int { for score := range m { if score <= target { return score } } return -1}
func max(a, b int) int { if a > b { return a } return b}
// RandomScores generates an array of random scoresfunc randomScores(n, v int) []int { scores := make([]int, n) rand.Seed(time.Now().UnixNano()) for i := 0; i < n; i++ { scores[i] = rand.Intn(v) } return scores}
// RandomOperations generates a 2D array of random operationsfunc randomOperations(n, m, v int) [][]int { operations := make([][]int, m) rand.Seed(time.Now().UnixNano()) for i := 0; i < m; i++ { operations[i] = make([]int, 3) if rand.Float32() < 0.5 { operations[i][0] = 1 operations[i][1] = rand.Intn(v) } else { operations[i][0] = 2 operations[i][1] = rand.Intn(n) operations[i][2] = rand.Intn(v) } } return operations}
// IsEqual checks if two arrays are equalfunc isEqual(arr1, arr2 []int) bool { if len(arr1) != len(arr2) { return false } for i := 0; i < len(arr1); i++ { if arr1[i] != arr2[i] { return false } } return true}
// Main function for testingfunc main() { N := 1000 M := 1000 V := 100000 testTimes := 100 fmt.Println("功能测试开始") for i := 0; i < testTimes; i++ { n := rand.Intn(N) + 1 m := rand.Intn(M) + 1 scores := randomScores(n, V) operations := randomOperations(n, m, V) ans1 := operateScores1(scores, operations) ans2 := operateScores2(scores, operations) if !isEqual(ans1, ans2) { fmt.Println("出错了!") } } fmt.Println("功能测试结束")
fmt.Println("性能测试开始") n := 100000 m := 100000 v := 100000000 scores := randomScores(n, v) operations := randomOperations(n, m, v) fmt.Println("总人数:", n) fmt.Println("操作数:", n) fmt.Println("值范围:", v) start := time.Now() operateScores2(scores, operations) end := time.Now() fmt.Println("运行时间:", end.Sub(start)) fmt.Println("性能测试结束")}
复制代码


c++完整代码如下:

#include <iostream>#include <vector>#include <map>#include <random>#include <ctime>
using namespace std;
class Bucket;
// Node represents a node in the bucketclass Node {public: int index; Node* last; Node* next;
void connectLastNext() { last->next = next; next->last = last; }};
// Bucket, scores stored in a sorted listclass Bucket {public: Node* head; Node* tail;
Bucket() { head = new Node(); tail = new Node(); head->index = -1; tail->index = -1; head->next = tail; tail->last = head; }
void add(Node* node) { node->last = tail->last; node->next = tail; tail->last->next = node; tail->last = node; }
void merge(Bucket* join) { if (join->head->next != join->tail) { tail->last->next = join->head->next; join->head->next->last = tail->last; join->tail->last->next = tail; tail->last = join->tail->last; join->head->next = join->tail; join->tail->last = join->head; } }};
vector<int> operateScores1(const vector<int>& scores, const vector<vector<int>>& operations) { int n = scores.size(); vector<int> ans(scores);
for (const auto& op : operations) { if (op[0] == 1) { for (int i = 0; i < n; i++) { ans[i] = max(ans[i], op[1]); } } else { ans[op[1]] = op[2]; } }
return ans;}
int floorKey(const map<int, Bucket*>& m, int target);
vector<int> operateScores2(const vector<int>& scores, const vector<vector<int>>& operations) { int n = scores.size(); vector<Node*> nodes(n); map<int, Bucket*> scoreBucketMap;
for (int i = 0; i < n; i++) { nodes[i] = new Node(); nodes[i]->index = i; if (scoreBucketMap.find(scores[i]) == scoreBucketMap.end()) { scoreBucketMap[scores[i]] = new Bucket(); } scoreBucketMap[scores[i]]->add(nodes[i]); }
for (const auto& op : operations) { if (op[0] == 1) { int floorKeyV = floorKey(scoreBucketMap, op[1] - 1);
if (floorKeyV != -1 && scoreBucketMap.find(op[1]) == scoreBucketMap.end()) { scoreBucketMap[op[1]] = new Bucket(); }
while (floorKeyV != -1) { scoreBucketMap[op[1]]->merge(scoreBucketMap[floorKeyV]); scoreBucketMap.erase(floorKeyV); floorKeyV = floorKey(scoreBucketMap, op[1] - 1); } } else { Node* cur = nodes[op[1]]; cur->connectLastNext();
if (scoreBucketMap.find(op[2]) == scoreBucketMap.end()) { scoreBucketMap[op[2]] = new Bucket(); }
scoreBucketMap[op[2]]->add(cur); } }
vector<int> ans(n); for (const auto& entry : scoreBucketMap) { int score = entry.first; Bucket* bucket = entry.second; Node* cur = bucket->head->next; while (cur != bucket->tail) { ans[cur->index] = score; cur = cur->next; } }
return ans;}
int floorKey(const map<int, Bucket*>& m, int target) { for (const auto& entry : m) { int score = entry.first; if (score <= target) { return score; } } return -1;}
int main() { int N = 1000; int M = 1000; int V = 100000; int testTimes = 100; cout << "功能测试开始" << endl; for (int i = 0; i < testTimes; i++) { int n = rand() % N + 1; int m = rand() % M + 1; vector<int> scores(n); vector<vector<int>> operations(m, vector<int>(3));
for (int j = 0; j < n; j++) { scores[j] = rand() % V; }
for (auto& op : operations) { if (rand() < 0.5) { op[0] = 1; op[1] = rand() % V; } else { op[0] = 2; op[1] = rand() % n; op[2] = rand() % V; } }
vector<int> ans1 = operateScores1(scores, operations); vector<int> ans2 = operateScores2(scores, operations);
if (ans1 != ans2) { cout << "出错了!" << endl; } } cout << "功能测试结束" << endl;
cout << "性能测试开始" << endl; int n = 1000000; int m = 1000000; int v = 1000000000; vector<int> scores(n); vector<vector<int>> operations(m, vector<int>(3));
for (int i = 0; i < n; i++) { scores[i] = rand() % v; }
for (auto& op : operations) { op[0] = rand() < 0.5 ? 1 : 2; op[1] = rand() % n; op[2] = rand() % v; }
cout << "总人数: " << n << endl; cout << "操作数: " << m << endl; cout << "值范围: " << v << endl; clock_t start = clock(); operateScores2(scores, operations); clock_t end = clock(); cout << "运行时间: " << double(end - start) / CLOCKS_PER_SEC << endl; cout << "性能测试结束" << endl;
return 0;}
复制代码



发布于: 刚刚阅读数: 4
用户头像

公众号:福大大架构师每日一题 2021-02-15 加入

公众号:福大大架构师每日一题

评论

发布
暂无评论
2023-06-18:给定一个长度为N的一维数组scores, 代表0~N-1号员工的初始得分, scores[i] = a, 表示i号员工一开始得分是a, 给定一个长度为M的二维数组operatio_golang_福大大架构师每日一题_InfoQ写作社区