[Codewar练习-java&c++]Twice linear(双线性)

这篇博客介绍了Codewar上的Twice linear问题,涉及汉明数字和N线性算法。文章分析了数组的生成规律,通过二叉树模型解释元素产生过程,并探讨了去重和排序的策略。博主提出了一种优化方法,通过从最小元素开始计算并去重,确保有序性。文章提供了Java和C++的优化代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:

段位:4

说明:

假设一个数组 arr,里面的元素是这样的规律:

1、arr[ 0 ] = 1;

2、每一个 arr[ i ] 都存在  2 * arr[ i ] + 1 和 3 * arr[ i ]  + 1 的元素在数组里面。

3、arr 是从小到大排序的数组

4、arr 的元素不重复

例子就是: arr = [1, 3, 4, 7, 9, 10, 13, 15, 19, 21, 22, 27, ...] (1 存在 2 * 1 + 1 和 3 * 1 + 1 的元素,3 和 4 也是)

然后输入一个数 n,要求返回 arr 从下标 1 开始的 第 n 个元素值

题目连接:https://www.codewars.com/kata/5672682212c8ecf83e000050

相关算法:

Hamming Numbers(汉明数字):https://blog.youkuaiyun.com/qq_28033719/article/details/115953335

N Linear(N线性):https://blog.youkuaiyun.com/qq_28033719/article/details/115956290

输入案例:

dbl_linear(10) should return 22 案例的数组数一下刚好第 10 个是 22

我的代码:

因为数组里面有 2 * arr[ i ] + 1 和 3 * arr[ i ] + 1 两种线性的元素存在,并且是 从小到大有序的,首先先看这些元素的产生:

1、元素产生,是一个二叉树:

从 1 开始 左边 x * 2 + 1 右边 x * 3 + 1 开始生成树

首先第2层存在  x * 2 + 1 < x * 3 + 1 的规律

然后第3层开始  7 10 9 13 这个排序开始无序

然后再到 第 5 层 开始 出现 31 这个元素 和 第 4 层的元素重复,并且得出 第5 层元素 存在 值 小于 第 4 层的元素 (31 < 40)

2、要求去重排序

一时间没有特别好的想法,肯定是每个元素计算,去重,排序,这样处理是最好的。

但是再观察可以发现:

arr = [1, 3, 4, 7, 9, 10, 13, 15, 19, 21, 22......]

     = [1, 1 * 2 + 1, 1 * 3 + 1, 3 * 2 + 1, 4 * 2 + 1, 3 * 3 + 1, 4 * 3 + 1,  7 * 2 + 1, 9 * 2 + 1,  10 * 2 + 1, 7 * 3 + 1....]

标记的数组里面的绿色排列就是 1 1 1 3 4 3 4 7 9 10 7.... 这个微妙的规律,不得不说,arr 的下标 1 开始的 元素都肯定是 前面某一个元素 通过一个线性计算得出的。

那么怎么取某个前面的元素,按照 arr 本来就是有序的规则,肯定是从下标 0 开始,最小的元素开始取,必定获得 经 x * 2 + 1 或者 x * 3 + 1 运算得出的符合下一个排序的元素值。

而且还得考虑去重,那么每次运算时候都判断下 * 2 或者 * 3 是否有相同的,有就修改即可。

因为这个计算是有序进行,所以不用考虑第几层出现更小的数据

先贴出优化的代码

Java代码:

class DoubleLinear {
    
    public static int dblLinear (int n) {
       int[] tempArr = new int[n + 1];
        tempArr[0] = 1;
        int ai = 1, bi = 1, av = 3, bv = 4;

        for(int i = 1; i <= n; i ++) {
            tempArr[i] = Math.min(av, bv);
            if(tempArr[i] == av) av = (tempArr[ai ++] << 1) + 1;
            if(tempArr[i] == bv) bv = (tempArr[bi ++] * 3) + 1;
        }
      return tempArr[n];
    }
}

C++代码:

class DoubleLinear
{
public:
    static int dblLinear(int n) {
      int *tempArr = new int[n + 1],
          a = 3, b = 4, aIdx = 0, bIdx = 0;
      tempArr[0] = 1;
      for(int i = 1; i <= n; i ++) {
        tempArr[i] = std::min(a, b);
        if(tempArr[i] == a) a = (tempArr[++ aIdx] << 1) + 1;
        if(tempArr[i] == b) b = tempArr[++ bIdx] * 3 + 1;
      }
      return tempArr[n];
    };

};

其实没有优化的话,直接暴力地用数组实现也行,还有更好的一个数据结构就是 java 的 sortset 可以排序并且去重,几乎是一举两得:

使用 sortset:

Java:

import java.util.*;
class DoubleLinear {
    
    public static int dblLinear (int n) {
        if (n == 0) return 1;
        SortedSet<Integer> u = new TreeSet<>();
        u.add(1);
        for(int i=0; i < n; i++) {
            int x = u.first();
            u.add((x << 1) + 1);
            u.add(x + x + x + 1);
            u.remove(x);
        }
        return u.first();
    }
}

也可用 bfs 广度搜索,然后再加个数组暴力地遍历,然后来个 hashset 记录重复数据,不过当数据量继续变大时候,这个就缺点更多了:

import java.util.Arrays;
import java.util.HashSet;

class DoubleLinear {
   private static int begin = 0, curIdx = 0;
   private static int[] queue = new int[1000000]; // 一百万长度暴力地遍历
    public static int dblLinear (int n) {
      HashSet<Integer> set = new HashSet<>(); // 另外需要去重
        begin = curIdx = 0;
        queue[curIdx ++] = 1;
        while(curIdx <= n) { // 开始 bfs
            int i = begin, end = curIdx;
            begin = curIdx;
            for(; i < end; i ++) {
                int[] arr = new int[]{(queue[i] << 1) + 1, queue[i] * 3 + 1};
                for(int j : arr) {
                    if(!set.contains(j)) {
                        queue[curIdx ++] = j;
                        set.add(j);
                    }
                }
            }
        }
        for(int x = 0; x < 3; x ++) { // 因为还有可能下面的层出现元素,所以还需要大概地多来几次
            int i = begin, end = curIdx;
            begin = curIdx;
            for(; i < end; i ++) {
                int[] arr = new int[]{(queue[i] << 1) + 1, queue[i] * 3 + 1};
                for(int j : arr) {
                    if(!set.contains(j)) {
                        queue[curIdx ++] = j;
                        set.add(j);
                    }
                }
            }
        }
        int[] res = Arrays.stream(queue, 0, curIdx).toArray(); // 最后直接截取长度并排序
        Arrays.sort(res);
        return res[n];
    }
}

 

 

 

 

1700+ K-Pop Idols Dataset可以用于训练各种机器学习或深度学习模型,例如: 1. 偶像分类模型:可以通过该数据集训练一个分类模型,将不同的偶像归类到不同的组别中,例如男子组、女子组、混合组等等。 2. 偶像特征提取模型:可以通过该数据集训练一个深度学习模型,提取出偶像的身高、体重、出道时间等特征,用于后续的分析和预测。 3. 偶像推荐模型:可以通过该数据集训练一个推荐模型,根据用户的兴趣和偏好,推荐他们可能喜欢的偶像。 以下是使用Python和PyTorch框架训练一个偶像分类模型的示例代码: ```python import pandas as pd import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import Dataset, DataLoader # 读取数据集 data = pd.read_csv("kpop_idols.csv") # 定义数据集类 class KpopDataset(Dataset): def __init__(self, data): self.data = data self.labels = {"M": 0, "F": 1} # 将男性和女性分别标记为0和1 def __len__(self): return len(self.data) def __getitem__(self, index): row = self.data.iloc[index] name = row["name"] gender = self.labels[row["gender"]] group = row["group"] debut = row["debut"] # 将偶像的信息转化为特征向量 features = [gender, debut] return torch.tensor(features), torch.tensor(group) # 定义分类模型 class KpopClassifier(nn.Module): def __init__(self): super(KpopClassifier, self).__init__() self.fc1 = nn.Linear(2, 10) self.fc2 = nn.Linear(10, 5) self.fc3 = nn.Linear(5, 3) def forward(self, x): x = torch.relu(self.fc1(x)) x = torch.relu(self.fc2(x)) x = self.fc3(x) return x # 训练模型 dataset = KpopDataset(data) dataloader = DataLoader(dataset, batch_size=32, shuffle=True) model = KpopClassifier() criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) for epoch in range(10): for features, labels in dataloader: optimizer.zero_grad() outputs = model(features.float()) loss = criterion(outputs, labels) loss.backward() optimizer.step() # 使用模型进行预测 gender = 0 # 0表示男性 debut = 2010 # 2010年出道 features = torch.tensor([gender, debut]) output = model(features.float()) group_index = torch.argmax(output) groups = ["EXO", "BTS", "TWICE"] group = groups[group_index] print(group) ``` 在上面的代码中,我们首先读取了1700+ K-Pop Idols Dataset数据集,并将每个偶像的性别、出道时间和所属组别作为特征,通过PyTorch框架训练了一个简单的分类模型。最后,我们使用训练好的模型对一个新的偶像进行预测,输出其可能所属的组别。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值