田忌赛马背后的算法决策 :: labuladong的算法小抄 #1014
Replies: 31 comments 15 replies
-
class Solution:
def advantageCount(self, nums1: List[int], nums2: List[int]) -> List[int]:
# 田忌赛马问题
hq = []
# 大顶堆
for i, num in enumerate(nums2):
heapq.heappush(hq, (-num, i))
nums1.sort()
# 双指针
left, right = 0, len(nums1) - 1
res = [0] * len(nums1)
while hq:
max_num, idx = heapq.heappop(hq)
max_sum = -max_num
if max_sum < nums1[right]:
res[idx] = nums1[right]
right -= 1
else:
res[idx] = nums1[left]
left += 1
return res |
Beta Was this translation helpful? Give feedback.
-
Python解法,空间使用超过99%+,没有用到堆,只用了二分搜索和排序 class Solution:
def advantageCount(self, nums1: List[int], nums2: List[int]) -> List[int]:
def helper(idx):
left, right = 0, len(nums1)-1
while left <= right:
mid = (left + right) // 2
if nums1[mid] > nums2[idx]:
right = mid - 1
else:
left = mid + 1
if left < len(nums1):
temp = left
else:
temp = 0
ans.append(nums1[temp])
nums1.pop(temp)
nums1.sort()
visited = [False] * len(nums1)
ans = []
for i in range(len(nums2)):
helper(i)
return ans |
Beta Was this translation helpful? Give feedback.
-
try this case: |
Beta Was this translation helpful? Give feedback.
-
@Xiaoyuan-Liu 没问题,这道题的答案并不唯一 |
Beta Was this translation helpful? Give feedback.
-
有一个小问题,就是PriorityQueue的构造方法为啥可以只有比较器,我一直没找到这种构造方法,但是我看网上都是直接用的,困扰我好久了 |
Beta Was this translation helpful? Give feedback.
-
@LakersHao java的话建议直接按住ctrl点进PriorityQueue的源码,可以看到有7个构造器,其中有一个是 |
Beta Was this translation helpful? Give feedback.
-
这个case没过 |
Beta Was this translation helpful? Give feedback.
-
go实现,大顶堆解法会有一个case不通过,换成sort直接两边排序可以ac import (
"container/heap"
"sort"
)
// @lc code=start
func advantageCount(nums1 []int, nums2 []int) []int {
// sort.Ints(nums1)
// b := make([][2]int, len(nums2))
// for i, n := range nums2 {
// b[i] = [2]int{n, i}
// }
// sort.Slice(b, func(i, j int) bool {
// return b[i][0] < b[j][0]
// })
// result := make([]int, len(nums1))
// left, right := 0, len(nums1)-1
// for i := len(b) - 1; i >= 0; i-- {
// val, idx := b[i][0], b[i][1]
// if nums1[right] > val {
// result[idx] = nums1[right]
// right--
// } else {
// result[idx] = nums1[left]
// left++
// }
// }
// return result
// nums1 升序排列
sort.Ints(nums1)
// nums2 降序排序,大顶堆
h := make(IntHeap, 0)
for i, val := range nums2 {
h = append(h, []int{i, val})
}
heap.Init(&h)
l, r := 0, len(nums1)-1
res := make([]int, len(nums1))
for h.Len() > 0 {
pair := h.Pop()
i, max := (pair.([]int))[0], (pair.([]int))[1]
if max < nums1[r] {
// 如果nums1[r]大于max,那就填入这个值
res[i] = nums1[r]
r--
} else {
// 否则用最小最混一下,田忌赛马
res[i] = nums1[l]
l++
}
}
return res
}
// 大顶堆,实现heap的interface
// h[x][0] 存储 index,h[x][1] 存储 value
type IntHeap [][]int
// 绑定Len方法
func (h IntHeap) Len() int {
return len(h)
}
// 绑定Less方法,这里用的是小于号,生成的是小根堆
func (h IntHeap) Less(i, j int) bool {
return h[i][1] > h[j][1]
}
// 绑定swap方法
func (h IntHeap) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
}
// pop、push 使用指针,因为改变了slice长度
// 绑定put方法,将index置为-1是为了标识该数据已经出了优先级队列了
func (h *IntHeap) Pop() interface{} {
old := *h
n := len(old)
item := old[0]
*h = old[1:n]
return item
}
// 绑定push方法
func (h *IntHeap) Push(x interface{}) {
*h = append(*h, x.([]int))
}
// @lc code=end |
Beta Was this translation helpful? Give feedback.
-
不用PQ可以么,直接Desend排序nums2? |
Beta Was this translation helpful? Give feedback.
-
打卡 |
Beta Was this translation helpful? Give feedback.
-
相等的情况呢?如果田忌是【8,6】,齐王是【8,7】,那么8=8的时候换6来打是可以的,优势增大;如果齐王是【8,5】呢,那样本来可以平一局赢一局的,结果变成输一局赢一局,优势减小了吧。所以相等情况是不是要根据下一个的值大小比较来确定顺序 |
Beta Was this translation helpful? Give feedback.
-
在看文章前尝试自己做了下这道题,对于排序后导致顺序错乱问题,可以写一个类来解决。对于两组马都按照战力值升序排列: class Solution {
class Horse {
int pos, weight;
boolean used;
}
public int[] advantageCount(int[] nums1, int[] nums2) {
int n = nums1.length;
int[] ans = new int[n];
Horse[] horses1 = new Horse[n];
Horse[] horses2 = new Horse[n];
for (int i = 0; i < n; i++) {
horses1[i] = new Horse();
horses1[i].pos = i;
horses1[i].weight = nums1[i];
horses2[i] = new Horse();
horses2[i].pos = i;
horses2[i].weight = nums2[i];
}
Arrays.sort(horses1, Comparator.comparingInt(o -> o.weight));
Arrays.sort(horses2, Comparator.comparingInt(o -> o.weight));
int p1 = 0, p2 = 0;
while (p1 < n) {
if (horses1[p1].weight > horses2[p2].weight) {
ans[horses2[p2].pos] = horses1[p1].weight;
horses1[p1].used = true;
horses2[p2].used = true;
p1++; p2++;
} else {
p1++;
}
}
p2 = n - 1;
// 从后往前找
for (int i = horses1.length - 1; i >= 0; i--) {
if (!horses1[i].used) {
while (ans[horses2[p2].pos] != 0) p2--;
ans[horses2[p2].pos] = horses1[i].weight;
}
}
return ans;
}
} |
Beta Was this translation helpful? Give feedback.
-
Test Case
我的 答案 #我的不比答案好?还是有什么我遗漏了? |
Beta Was this translation helpful? Give feedback.
-
class Solution:
def advantageCount(self, nums1: List[int], nums2: List[int]) -> List[int]:
nums1_ = sorted(nums1)
nums2_ = sorted(enumerate(nums2), key=lambda p: p[1])
left = 0
right = len(nums1) - 1
res = [-1] * len(nums1)
while nums2_:
i, maxval = nums2_.pop()
if maxval < nums1_[right]:
res[i] = nums1_[right]
right -= 1
else:
res[i] = nums1_[left]
left += 1
return res |
Beta Was this translation helpful? Give feedback.
-
20230110 打卡。田忌赛马的思想真牛 |
Beta Was this translation helpful? Give feedback.
-
js写法,时间复杂度O(nlogn)
|
Beta Was this translation helpful? Give feedback.
-
优势洗牌里面chatgpt给出的c++解法有问题,一是语法错误(priority_queue在插入数据时没有make_pair),二是没有重载运算符,导致priority_queue进行排序时按照第一个数字i排序, /*
* @lc app=leetcode.cn id=870 lang=cpp
*
* [870] 优势洗牌
*/
// @lc code=start
class Solution {
public:
vector<int> advantageCount(vector<int> &nums1, vector<int> &nums2) {
priority_queue<pair<int, int>> maxpl;
for (int i = 0; i < nums1.size(); i++) {
maxpl.push(make_pair(nums2[i],i));
}
int left = 0, right = nums1.size() - 1;
vector<int> res(nums1.size());
sort(nums1.begin(), nums1.end());
while (!maxpl.empty()) {
auto [maxp,i] = maxpl.top();
maxpl.pop();
if (nums1[right] > maxp) {
res[i] = nums1[right];
cout<<res[i]<<maxp<<i<<endl;
right--;
} else {
res[i] = nums1[left];
cout<<res[i]<<maxp<<i<<endl;
left++;
}
}
return res;
}
};
// @lc code=end |
Beta Was this translation helpful? Give feedback.
-
chatgpt给出的js解法前半部分有些问题, 更正了下
|
Beta Was this translation helpful? Give feedback.
-
打卡,附上详细注解的Java代码 //算法的思路其实很简单:如果我们两个最好的比较nums1可以干过nums2,那就让nums1最好的上,否则让nums1中最差的去送人头
public int[] advantageCount(int[] nums1, int[] nums2) {
int n=nums1.length;
//对nums1进行一个排序,升序排列
Arrays.sort(nums1);
//因为nums2是不能改变顺序的,我们是和nums2进行对弈的,所以使用一个辅助数据结构来存储排序的结构
//优先级队列中自定义了比较规则从大到小排列了,每个节点存储的结构是[索引,值]
PriorityQueue<int[]> priorityQueue = new PriorityQueue<>((int[] pair1, int[] pair2) -> {
return pair2[1] - pair1[1];
});
for (int i = 0; i < nums2.length; i++) {
priorityQueue.offer(new int[]{i,nums2[i]});
}
//两个人开始对弈
int left=0,right=n-1;
int[] res=new int[n];
while(!priorityQueue.isEmpty()){
int[] poll = priorityQueue.poll();
if(nums1[right]>poll[1]){
//nums1中最好的可以打过nums2中最好的,直接干
//结果的位置要根据nums2的索引顺序来确定,因为是和nums2进行对弈的
res[poll[0]]=nums1[right];
right--;
}else{
//干不过,让最差的去送
res[poll[0]]=nums1[left];
left++;
}
}
return res;
} |
Beta Was this translation helpful? Give feedback.
-
补充一个cpp的版本,东哥这里的cpp版本答案有点偏差: |
Beta Was this translation helpful? Give feedback.
-
博主的c++代码存在错误,maxpq的顺序因为nums2[i],i 因为队列以第一个元素排大小。 |
Beta Was this translation helpful? Give feedback.
-
更新一下pass的cpp代码,如果用chatgpt翻译过来的cpp不太正确。 class Solution {
public:
vector<int> advantageCount(vector<int>& nums1, vector<int>& nums2) {
int n = nums1.size();
// 给 nums2 升序排序
priority_queue<pair<int, int>> maxpq;
for (int i = 0; i < n; i++) {
maxpq.emplace(nums2[i] , i);
}
// 给 nums1 升序排序
sort(nums1.begin(), nums1.end());
// nums1[left] 是最小值,nums1[right] 是最大值
int left = 0, right = n - 1;
vector<int> res(n);
while (!maxpq.empty()) {
auto [maxval, i] = maxpq.top();
maxpq.pop();
if (maxval < nums1[right]) {
// 如果 nums1[right] 能胜过 maxval,那就自己上
res[i] = nums1[right];
right--;
} else {
// 否则用最小值混一下,养精蓄锐
res[i] = nums1[left];
left++;
}
}
return res;
}
}; |
Beta Was this translation helpful? Give feedback.
-
非常感谢您的邮件。
|
Beta Was this translation helpful? Give feedback.
-
非常感谢您的邮件。
|
Beta Was this translation helpful? Give feedback.
-
我想到的思路是从最差的马开始找,各自从所有未分配比赛的马中找一匹最差的马,如果田忌能赢,就用这匹马,这样用最差的马来获取胜利是最“节约“的办法。如果田忌不能赢,因为这匹马必然不会带来任何一场胜利,因此就让他去与齐王最厉害的马比赛,然后再比较当前田忌最差的马能否嬴齐王最差的马,以此类推,直到所有的马都被分配比赛。 |
Beta Was this translation helpful? Give feedback.
-
非常感谢您的邮件。
|
Beta Was this translation helpful? Give feedback.
-
cpp的代码错了,因为优先队列没有自定义排序 |
Beta Was this translation helpful? Give feedback.
-
非常感谢您的邮件。
|
Beta Was this translation helpful? Give feedback.
-
文章链接点这里:田忌赛马背后的算法决策
评论礼仪 见这里,违者直接拉黑。
Beta Was this translation helpful? Give feedback.
All reactions