一、问题描述
题目描述
给定一个乱序的数组,删除所有的重复元素,使得每个元素只出现一次,并且按照出现的次数从高到低进行排序,相同出现次数按照第一次出现顺序进行先后排序。
输入描述
一个数组
输出描述
去重排序后的数组
用例
用例 1
输入:
1,3,3,3,2,4,4,4,5
输出:
3,4,1,2,5
解题思路
-
统计每个元素的出现次数:
- 使用一个哈希表(字典)来记录每个元素的出现次数。
- 同时,记录每个元素第一次出现的位置,以便在出现次数相同的情况下,保持原始顺序。
-
构建带出现次数和原始索引的数组:
- 遍历原数组,将每个元素及其出现次数和第一次出现的索引存储在一个新的数组中。
-
排序:
- 使用自定义排序函数对新数组进行排序。
- 排序的关键字是出现次数(降序)和原始索引(升序)。
-
提取排序后的元素:
- 从排序后的数组中提取元素,构建最终的去重排序后的数组。
详细步骤
-
读取输入:
- 从标准输入读取一个数组。
-
统计每个元素的出现次数和第一次出现的索引:
- 创建一个哈希表
countMap
,键为元素,值为一个对象{ count: 0, firstIndex: -1 }
。 - 遍历数组,更新每个元素的出现次数和第一次出现的索引。
- 创建一个哈希表
-
构建带出现次数和原始索引的数组:
- 创建一个新数组
elements
,每个元素是一个对象{ value, count, firstIndex }
。 - 遍历原数组,将每个元素及其出现次数和第一次出现的索引添加到
elements
中。
- 创建一个新数组
-
排序:
- 使用
Array.prototype.sort
方法对elements
进行排序。 - 排序的关键字是出现次数(降序)和原始索引(升序)。
- 使用
-
提取排序后的元素:
- 从排序后的
elements
中提取value
,构建最终的去重排序后的数组。
- 从排序后的
-
输出结果:
- 输出去重排序后的数组。
用例解释
用例 1
- 输入:
1,3,3,3,2,4,4,4,5
- 输出:
3,4,1,2,5
解释:
- 统计每个元素的出现次数:
1
出现 1 次3
出现 3 次2
出现 1 次4
出现 3 次5
出现 1 次
- 按照出现次数从高到低排序,相同出现次数按照第一次出现顺序排序:
3
和4
出现 3 次,3
先出现1
、2
、5
出现 1 次,1
先出现,2
次之,5
最后
- 最终结果为
3,4,1,2,5
通过上述步骤,我们可以高效地对数组进行去重和排序,确保结果按出现次数从高到低排序,相同出现次数按第一次出现顺序排序。这种方法的时间复杂度主要由排序操作决定,为 O(n log n)
,其中 n
是数组的长度。
二、JavaScript算法源码
以下是 JavaScript 代码的详细中文注释和逻辑讲解:
JavaScript 代码
/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline"); // 引入 readline 模块,用于读取控制台输入// 创建 readline 接口
const rl = readline.createInterface({input: process.stdin, // 输入流为标准输入output: process.stdout, // 输出流为标准输出
});// 监听每一行输入
rl.on("line", (line) => {// 将输入行按逗号分隔成数组const arr = line.split(",");// 调用算法并输出结果console.log(getResult(arr));
});/* 算法逻辑 */
function getResult(arr) {// 定义两个对象:// count:用于统计每个字符串出现的次数// first:用于记录每个字符串第一次出现的索引const count = {};const first = {};// 遍历输入数组for (let i = 0; i < arr.length; i++) {const s = arr[i]; // 当前字符串// 统计字符串出现的次数if (count[s] == undefined) count[s] = 0; // 如果未记录过,初始化为 0count[s]++; // 次数加 1// 记录字符串第一次出现的索引if (first[s] == undefined) first[s] = i; // 如果未记录过,记录当前索引}// 返回排序后的结果return [...Object.keys(first)] // 获取所有字符串(去重).sort((a, b) =>// 排序规则:// 1. 按出现次数降序排列// 2. 如果出现次数相同,按第一次出现的索引升序排列count[a] != count[b] ? count[b] - count[a] : first[a] - first[b]).join(","); // 将排序后的数组用逗号拼接成字符串
}
代码逻辑讲解
1. 输入处理
- 使用
readline
模块读取控制台输入。 - 监听
line
事件,每次读取一行输入。 - 将输入行按逗号分隔成数组
arr
。
2. 统计信息
- 定义两个对象:
count
:用于统计每个字符串出现的次数。first
:用于记录每个字符串第一次出现的索引。
- 遍历数组
arr
:- 更新
count
中每个字符串的出现次数。 - 更新
first
中每个字符串的第一次出现索引。
- 更新
3. 排序规则
- 使用
Object.keys(first)
获取所有字符串(去重)。 - 对字符串数组进行排序:
- 优先按出现次数降序排列。
- 如果出现次数相同,按第一次出现的索引升序排列。
4. 输出结果
- 将排序后的数组用逗号拼接成字符串并返回。
代码细节解析
1. readline
模块
- 用于读取控制台输入。
rl.on("line", (line) => { ... })
监听每一行输入。
2. split()
- 将字符串按指定分隔符拆分成数组。
line.split(",")
将输入行按逗号分隔成数组。
3. count
对象
- 用于统计每个字符串出现的次数。
count[s]++
更新字符串s
的出现次数。
4. first
对象
- 用于记录每个字符串第一次出现的索引。
first[s] = i
记录字符串s
的第一次出现索引。
5. Object.keys()
- 获取对象的所有键(字符串)。
Object.keys(first)
获取所有字符串(去重)。
6. sort()
- 对数组进行排序。
sort((a, b) => ...)
自定义排序规则:- 优先按出现次数降序排列。
- 如果出现次数相同,按第一次出现的索引升序排列。
7. join()
- 将数组拼接成字符串。
.join(",")
用逗号拼接数组。
示例运行
输入
apple,banana,apple,orange,banana,apple
步骤解析
- 输入行按逗号分隔成数组:
arr = ["apple", "banana", "apple", "orange", "banana", "apple"]
- 统计信息:
count = { apple: 3, banana: 2, orange: 1 }
first = { apple: 0, banana: 1, orange: 3 }
- 排序规则:
- 按出现次数降序排列:
apple
(3) >banana
(2) >orange
(1)
- 如果出现次数相同,按第一次出现的索引升序排列。
- 按出现次数降序排列:
- 排序后的数组:
["apple", "banana", "orange"]
- 拼接成字符串:
"apple,banana,orange"
- 输出结果:
apple,banana,orange
总结
- 功能:统计字符串数组中每个字符串的出现次数,并按出现次数降序排列;如果次数相同,按第一次出现的索引升序排列。
- 适用场景:处理字符串统计和排序问题。
- 注意事项:
- 如果输入为空,结果为空字符串。
- 如果所有字符串出现次数相同,按第一次出现的索引排序。
如果有其他问题,欢迎随时提问!
三、Java算法源码
以下是 Java 代码的详细中文注释和逻辑讲解:
Java 代码
import java.util.HashMap; // 引入 HashMap,用于存储键值对
import java.util.Scanner; // 引入 Scanner,用于读取控制台输入
import java.util.StringJoiner; // 引入 StringJoiner,用于拼接字符串public class Main {public static void main(String[] args) {// 创建 Scanner 对象,用于读取控制台输入Scanner sc = new Scanner(System.in);// 读取一行输入,并按逗号分隔成字符串数组String[] arr = sc.nextLine().split(",");// 调用算法并输出结果System.out.println(getResult(arr));}// 算法逻辑public static String getResult(String[] arr) {// 定义两个 HashMap:// count:用于统计每个字符串出现的次数// first:用于记录每个字符串第一次出现的索引HashMap<String, Integer> count = new HashMap<>();HashMap<String, Integer> first = new HashMap<>();// 遍历输入数组for (int i = 0; i < arr.length; i++) {String s = arr[i]; // 当前字符串// 统计字符串出现的次数count.put(s, count.getOrDefault(s, 0) + 1); // 如果未记录过,初始化为 0,然后加 1// 记录字符串第一次出现的索引first.putIfAbsent(s, i); // 如果未记录过,记录当前索引}// 创建 StringJoiner 对象,用于拼接字符串StringJoiner sj = new StringJoiner(",");// 对字符串进行排序并拼接first.keySet().stream() // 获取所有字符串(去重).sorted((a, b) -> {// 排序规则:// 1. 按出现次数降序排列int countA = count.get(a);int countB = count.get(b);if (countA != countB) {return countB - countA; // 降序排列} else {// 2. 如果出现次数相同,按第一次出现的索引升序排列int firstA = first.get(a);int firstB = first.get(b);return firstA - firstB; // 升序排列}}).forEach(s -> sj.add(s)); // 将排序后的字符串添加到 StringJoiner 中// 返回拼接后的字符串return sj.toString();}
}
代码逻辑讲解
1. 输入处理
- 使用
Scanner
读取控制台输入。 - 将输入行按逗号分隔成字符串数组
arr
。
2. 统计信息
- 定义两个
HashMap
:count
:用于统计每个字符串出现的次数。first
:用于记录每个字符串第一次出现的索引。
- 遍历数组
arr
:- 更新
count
中每个字符串的出现次数。 - 更新
first
中每个字符串的第一次出现索引。
- 更新
3. 排序规则
- 使用
first.keySet().stream()
获取所有字符串(去重)。 - 对字符串进行排序:
- 优先按出现次数降序排列。
- 如果出现次数相同,按第一次出现的索引升序排列。
4. 输出结果
- 使用
StringJoiner
将排序后的字符串拼接成逗号分隔的字符串并返回。
代码细节解析
1. Scanner
- 用于读取控制台输入。
sc.nextLine()
读取一行输入。split(",")
将输入行按逗号分隔成数组。
2. HashMap
- 用于存储键值对。
count.put(s, count.getOrDefault(s, 0) + 1)
更新字符串s
的出现次数。first.putIfAbsent(s, i)
记录字符串s
的第一次出现索引。
3. StringJoiner
- 用于拼接字符串。
new StringJoiner(",")
创建一个以逗号分隔的拼接器。sj.add(s)
将字符串s
添加到拼接器中。
4. stream()
- 将集合转换为流,便于操作。
first.keySet().stream()
获取所有字符串(去重)。
5. sorted()
- 对流中的元素进行排序。
- 自定义排序规则:
- 优先按出现次数降序排列。
- 如果出现次数相同,按第一次出现的索引升序排列。
6. forEach()
- 对流中的每个元素执行操作。
sj.add(s)
将排序后的字符串添加到StringJoiner
中。
示例运行
输入
apple,banana,apple,orange,banana,apple
步骤解析
- 输入行按逗号分隔成数组:
arr = ["apple", "banana", "apple", "orange", "banana", "apple"]
- 统计信息:
count = {apple=3, banana=2, orange=1}
first = {apple=0, banana=1, orange=3}
- 排序规则:
- 按出现次数降序排列:
apple
(3) >banana
(2) >orange
(1)
- 如果出现次数相同,按第一次出现的索引升序排列。
- 按出现次数降序排列:
- 排序后的数组:
["apple", "banana", "orange"]
- 拼接成字符串:
"apple,banana,orange"
- 输出结果:
apple,banana,orange
总结
- 功能:统计字符串数组中每个字符串的出现次数,并按出现次数降序排列;如果次数相同,按第一次出现的索引升序排列。
- 适用场景:处理字符串统计和排序问题。
- 注意事项:
- 如果输入为空,结果为空字符串。
- 如果所有字符串出现次数相同,按第一次出现的索引排序。
如果有其他问题,欢迎随时提问!
四、Python算法源码
以下是 Python 代码的详细中文注释和逻辑讲解:
Python 代码
# 输入获取
arr = input().split(",") # 读取控制台输入,并按逗号分隔成列表# 算法入口
def getResult(arr):# 定义两个字典:# count:用于统计每个字符串出现的次数# first:用于记录每个字符串第一次出现的索引count = {}first = {}# 遍历输入列表for i in range(len(arr)):s = arr[i] # 当前字符串# 统计字符串出现的次数if count.get(s) is None: # 如果未记录过,初始化为 0count[s] = 0count[s] += 1 # 次数加 1# 记录字符串第一次出现的索引if first.get(s) is None: # 如果未记录过,记录当前索引first[s] = i# 获取所有字符串(去重)tmp = list(first.keys())# 对字符串进行排序tmp.sort(key=lambda x: (-count[x], first[x])) # 排序规则:按出现次数降序排列,如果次数相同,按第一次出现的索引升序排列# 将排序后的列表用逗号拼接成字符串return ",".join(tmp)# 算法调用
print(getResult(arr)) # 输出结果
代码逻辑讲解
1. 输入处理
- 使用
input()
读取控制台输入。 - 将输入行按逗号分隔成列表
arr
。
2. 统计信息
- 定义两个字典:
count
:用于统计每个字符串出现的次数。first
:用于记录每个字符串第一次出现的索引。
- 遍历列表
arr
:- 更新
count
中每个字符串的出现次数。 - 更新
first
中每个字符串的第一次出现索引。
- 更新
3. 排序规则
- 使用
list(first.keys())
获取所有字符串(去重)。 - 对字符串进行排序:
- 优先按出现次数降序排列。
- 如果出现次数相同,按第一次出现的索引升序排列。
4. 输出结果
- 将排序后的列表用逗号拼接成字符串并返回。
代码细节解析
1. input()
- 用于读取控制台输入。
split(",")
将输入行按逗号分隔成列表。
2. 字典操作
count.get(s) is None
:检查字符串s
是否在字典中。count[s] = 0
:如果未记录过,初始化为 0。count[s] += 1
:更新字符串s
的出现次数。first.get(s) is None
:检查字符串s
是否在字典中。first[s] = i
:记录字符串s
的第一次出现索引。
3. list(first.keys())
- 获取字典
first
的所有键(字符串),并转换为列表。
4. sort()
- 对列表进行排序。
key=lambda x: (-count[x], first[x])
自定义排序规则:- 优先按出现次数降序排列(
-count[x]
表示降序)。 - 如果出现次数相同,按第一次出现的索引升序排列。
- 优先按出现次数降序排列(
5. join()
- 将列表拼接成字符串。
",".join(tmp)
用逗号拼接列表。
示例运行
输入
apple,banana,apple,orange,banana,apple
步骤解析
- 输入行按逗号分隔成列表:
arr = ["apple", "banana", "apple", "orange", "banana", "apple"]
- 统计信息:
count = {"apple": 3, "banana": 2, "orange": 1}
first = {"apple": 0, "banana": 1, "orange": 3}
- 排序规则:
- 按出现次数降序排列:
apple
(3) >banana
(2) >orange
(1)
- 如果出现次数相同,按第一次出现的索引升序排列。
- 按出现次数降序排列:
- 排序后的列表:
["apple", "banana", "orange"]
- 拼接成字符串:
"apple,banana,orange"
- 输出结果:
apple,banana,orange
总结
- 功能:统计字符串列表中每个字符串的出现次数,并按出现次数降序排列;如果次数相同,按第一次出现的索引升序排列。
- 适用场景:处理字符串统计和排序问题。
- 注意事项:
- 如果输入为空,结果为空字符串。
- 如果所有字符串出现次数相同,按第一次出现的索引排序。
如果有其他问题,欢迎随时提问!
五、C/C++算法源码:
以下是 C++ 代码的详细中文注释和逻辑讲解:
C++ 代码
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <algorithm>using namespace std;// 算法入口
string getResult(vector<string>& arr) {// 定义两个 map:// count:用于统计每个字符串出现的次数// first:用于记录每个字符串第一次出现的索引map<string, int> count;map<string, int> first;// 遍历输入数组for (int i = 0; i < arr.size(); i++) {string s = arr[i]; // 当前字符串// 统计字符串出现的次数if (count.find(s) == count.end()) { // 如果未记录过,初始化为 0count[s] = 0;}count[s]++; // 次数加 1// 记录字符串第一次出现的索引if (first.find(s) == first.end()) { // 如果未记录过,记录当前索引first[s] = i;}}// 获取所有字符串(去重)vector<string> tmp;for (auto& pair : first) {tmp.push_back(pair.first);}// 对字符串进行排序sort(tmp.begin(), tmp.end(), [&](const string& a, const string& b) {// 排序规则:// 1. 按出现次数降序排列if (count[a] != count[b]) {return count[a] > count[b];} else {// 2. 如果出现次数相同,按第一次出现的索引升序排列return first[a] < first[b];}});// 将排序后的列表用逗号拼接成字符串string result;for (int i = 0; i < tmp.size(); i++) {result += tmp[i];if (i != tmp.size() - 1) {result += ",";}}return result;
}int main() {// 输入获取string input;getline(cin, input); // 读取一行输入// 将输入按逗号分隔成数组vector<string> arr;size_t pos = 0;while ((pos = input.find(",")) != string::npos) {arr.push_back(input.substr(0, pos));input.erase(0, pos + 1);}arr.push_back(input); // 添加最后一个字符串// 算法调用cout << getResult(arr) << endl;return 0;
}
代码逻辑讲解
1. 输入处理
- 使用
getline(cin, input)
读取控制台输入。 - 将输入行按逗号分隔成字符串数组
arr
。
2. 统计信息
- 定义两个
map
:count
:用于统计每个字符串出现的次数。first
:用于记录每个字符串第一次出现的索引。
- 遍历数组
arr
:- 更新
count
中每个字符串的出现次数。 - 更新
first
中每个字符串的第一次出现索引。
- 更新
3. 排序规则
- 使用
vector<string> tmp
存储所有字符串(去重)。 - 对字符串进行排序:
- 优先按出现次数降序排列。
- 如果出现次数相同,按第一次出现的索引升序排列。
4. 输出结果
- 将排序后的列表用逗号拼接成字符串并返回。
代码细节解析
1. getline(cin, input)
- 用于读取控制台输入的一行内容。
2. 字符串分割
- 使用
find
和substr
将输入行按逗号分隔成字符串数组arr
。
3. map
- 用于存储键值对。
count.find(s) == count.end()
:检查字符串s
是否在map
中。count[s] = 0
:如果未记录过,初始化为 0。count[s]++
:更新字符串s
的出现次数。first.find(s) == first.end()
:检查字符串s
是否在map
中。first[s] = i
:记录字符串s
的第一次出现索引。
4. sort()
- 对
vector
进行排序。 - 自定义排序规则:
- 优先按出现次数降序排列(
count[a] > count[b]
)。 - 如果出现次数相同,按第一次出现的索引升序排列(
first[a] < first[b]
)。
- 优先按出现次数降序排列(
5. 字符串拼接
- 使用
string result
存储结果。 - 遍历排序后的列表,用逗号拼接字符串。
示例运行
输入
apple,banana,apple,orange,banana,apple
步骤解析
- 输入行按逗号分隔成数组:
arr = ["apple", "banana", "apple", "orange", "banana", "apple"]
- 统计信息:
count = {"apple": 3, "banana": 2, "orange": 1}
first = {"apple": 0, "banana": 1, "orange": 3}
- 排序规则:
- 按出现次数降序排列:
apple
(3) >banana
(2) >orange
(1)
- 如果出现次数相同,按第一次出现的索引升序排列。
- 按出现次数降序排列:
- 排序后的列表:
["apple", "banana", "orange"]
- 拼接成字符串:
"apple,banana,orange"
- 输出结果:
apple,banana,orange
总结
- 功能:统计字符串数组中每个字符串的出现次数,并按出现次数降序排列;如果次数相同,按第一次出现的索引升序排列。
- 适用场景:处理字符串统计和排序问题。
- 注意事项:
- 如果输入为空,结果为空字符串。
- 如果所有字符串出现次数相同,按第一次出现的索引排序。
如果有其他问题,欢迎随时提问!