介绍一 Triplet Loss的原理, 其中的样本分为哪几类?可以用于哪些场景?
Triplet Loss是一种用于训练神经网络的损失函数,主要用于学习映射函数,将样本映射到低维空间中,使得同一类别的样本距离尽可能近,不同类别的样本距离尽可能远。
在Triplet Loss中,每个样本被分为三类:Anchor,Positive和Negative。其中Anchor表示一个锚点样本,Positive表示和Anchor属于同一类别的样本,Negative表示和Anchor不属于同一类别的样本。
Triplet Loss的原理是,对于一个Anchor样本,选择与其属于同一类别的Positive样本和不属于同一类别的Negative样本,计算Anchor到Positive的距离和Anchor到Negative的距离,使得这两个距离之间的差距大于一定的阈值,从而让模型学习到对同一类别的样本更为相似,对不同类别的样本更为不同的特征表示。
Triplet Loss可以用于许多场景,例如人脸识别、图像检索、推荐系统等。在这些场景中,Triplet Loss可以帮助模型学习到区分不同类别样本的特征,从而提高模型的准确性和鲁棒性。
T1 好数组
开始认为是一个dp问题,最后变成了求通项公式。。
通项公式为:
T1:数学递推 递推后的式子为fn=(n-1)*2^(n+1) 用快速幂计算即可
通过快速幂求解即可,注意类型为long long:
#define MOD 1000000007
typedef long long ll;
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型
* @return int整型
*/
ll fastpow(ll n, ll val){
if(n == 1) return val;
if(n == 0) return 1;
ll x = fastpow(n/2, val);
return n % 2 ? ((x*x) % MOD*val) % MOD : (x*x) % MOD;
}
int fun(int n) {
return (ll)((n-1)*fastpow(n+1, 2)) % MOD;
}
};
为啥我第一题用了快速幂也不可以呀?
应该是long long的问题 int定义的话不行,第一题测试样例很恶心
第一题怎么退出来的公式啊
手玩,等比数列求和,感觉像是高中数学题
T2 二叉树
小红拿到了一棵叉树, 定义每个节点的价值为子树节点乘积的末尾0的数量。
现在请你返回一棵叉树, 树的结构和给定的二叉树相同,将每个节点的权值替换为该节点的价值。
- 二叉树节点数不超过 1 0 5 10^5 105
- 二叉树每个节点的权值都是不超过 1 0 9 10^9 109的正整数。
T2:
简单DFS
题目的意思是
- 求每个节点的子树所有元素乘积中0的个数(10->1 100->2 500->2)
自定向下DFS统计每个元素%2的数量a和%5的数量b即可
求一个和 乘积中0的个数转换为min(a,b)
class Solution {
public:
TreeNode* valueOfTree(TreeNode* root) {
// write code here
dfs(root);
return root;
}
pair<int,int> dfs(TreeNode* node){
if(node == nullptr){
return {0, 0};
}
auto l = dfs(node->left);
auto r = dfs(node->right);
auto cur = cal(node->val);
auto n2 = cur.first + l.first + r.first;
auto n5 = cur.second + l.second + r.second;
node->val = min(n2, n5);
return {n2, n5};
}
//末尾0的数量与因子2和5的数量有关系
pair<int,int> cal(int num){
int n2 = 0, n5 = 0;
while(num%2 == 0){
num /= 2;
n2 += 1;
}
while(num%5 == 0){
num /= 5;
n5 += 1;
}
return {n2,n5};
}
};
T3 构造一个大小是 n*(n+ 1)/2的数组
给定正整数n,小红希望你构造一个大小是 n*(n+ 1)/2的数组,
有1个1, 2个2, …n个n,且任意两个相邻元素都不相等。你能帮帮她吗?
答案不唯一,
有多解时输出任意合法解均可通过。
数据范围: 1 < n< 500
示例1
- 输入
3 - 输出
[3,2,3,2,3,1]
T3:贪心
优先存放剩余最多的数(用一个大根堆记录每个数字剩余的次数 如果堆顶元素和当前元素不相同
- 则直接push堆顶元素 堆顶元素的数量-1
如果相同 pop一下 在push堆顶元素
- 再push一下之前pop的元素即可)
第三题很简单,就321 32,4321 432 43,。。。不用贪心,两行代码解决了
- 就两个for循环
class Solution {
public:
vector<int> fun(int n) {
// write code here
int len = n*(n+1) / 2;
vector<int> ans(len, 0);
ans[0] = n;
int start = 1;
int j = 1;
for(int i=1; i<len; i++){
ans[i] = j++;
if(j > n){
start += 1;
j = start;
}
}
return ans;
}
};
def construct_array(n):
arr = [0] * (n * (n + 1) // 2)
index = 0
for i in range(1, n+1):
count = i
while count > 0:
arr[index] = i
index += 2*i if count == i else 1
count -= 1
return arr
函数construct_array(n)会返回一个符合要求的长度为n*(n+1)/2的数组。该算法的思路是对于每个数字i,将它重复i次放入数组中,但是每隔i个位置跳过一个位置,这样可以保证相邻元素不相等。
例如,当n=3时,构造的数组应该是[1,2,1,3,2,3]。在该算法中,我们首先初始化一个长度为n*(n+1)/2的数组,然后从1到n枚举每个数字i。对于每个数字i,我们将其重复i次,然后按照上述规则放入数组中。具体地,我们需要维护一个指针index,它表示当前应该将数字i插入的位置。然后我们从i开始,将i插入到数组的第index个位置。接着,如果我们还有剩余的i需要插入,就将index跳过2*i个位置,因为这样才能保证相邻元素不相等。如果我们只剩下1个i需要插入,就将index跳过1个位置。
最后,返回构造好的数组即可。