高级算法第一次课堂练习A班

1.按数值个数排序

描述

给定整数数组,请根据元素的频率对数组进行排序。 例如,如果输入数组是{2,3,2,4,5,12,12,2,3,3,3,12},则将该数组修改为{3,3,3,3,2,2, 2,12,12,4,5}。 如果两个元素的频率相同,则以升序打印。

Solution

按出现频次排序,那么我们只需要统计每个数字出现的次数,以数字出现的次数为key进行排序,最后从头到尾输出排序后的数字个数。

时间复杂度 O(nlogn)

空间复杂度O(n)

Python

import collections
# 对数列按照出现频次排序
def frecuncySort(nums):
    return [num * times for num, times in collections.Counter(nums).most_common()]

# IO输入输出
N = int(input())
for i in range(N):
    l = input()
    nums = list(map(int, input().split()))
    nums = map(str, frecuncySort(nums))
    out = ' '.join(nums)
    print(out)

Java

    public static List<Long> frecuncySort(List<Long> nums){
        // 计算频次,获取频次与数字对应的pairs
        Map<Long, Long> count = nums.stream().collect(Collectors.groupingBy(i -> i, Collectors.counting()));
        List<Pair> pairs = count.keySet().stream().map(key -> new Pair(key, count.get(key))).collect(Collectors.toList());

        // 按照频次对数字排序
        Collections.sort(pairs, (p1, p2) -> {
            // 频次相同按照数字大小排序
            if (p1.cnt == p2.cnt)
                return p1.value > p2.value ? 1:-1;
            return p1.cnt < p2.cnt ? 1:-1;
        });

        // 输出
        for(int i = 0; i < nums.size(); i++){
            nums.set(i, pairs.get(0).value);
            pairs.get(0).cnt--;
            if (pairs.get(0).cnt == 0)
                pairs.remove(0);
        }
        return nums;
    }

    public static class Pair{
        long value, cnt;

        Pair(long value, long cnt) {
            this.value = value;
            this.cnt = cnt;
        }
    }

2. 最小交换次数

描述

给定一个由N个不同的elements组成的数组,找到对数组进行排序所需的最小交换次数。您需要完成该函数,该函数返回一个表示对数组进行排序所需的最小交换次数的整数。

Solution

方法一:

遍历数组,判断当前元素是否在最终位置,否则把它交换到它的最终位置,(即每次交换至少让其中一个元素被放到其最终位置),统计总交换次数。

怎么判断当前元素是否在最终位置呢?

可以先对数组排序,得到每个数字对应最终位置的map。

python

def minswap(nums):
    # 排序
    snums = sorted(nums)
    # 位置数组
    inums = {snums[i]: i for i in range(len(snums))}
    count = 0
    for i in range(len(nums)):
        target_i = inums[nums[i]]
        while target_i != i:
            nums[i], nums[target_i] = nums[target_i], nums[i]
            count += 1
            target_i = inums[nums[i]]
    return count

java

public int minswap(List<Integer> nums){
    List<Integer> snums = new ArrayList<>();
    snums.addAll(nums);
    Collections.sort(snums);

    // 位置数组
    Map<Integer, Integer> inums = new HashMap<>();
    for (int i = 0; i<snums.size(); i++)
        inums.put(snums.get(i), i);

    int count = 0;
    for (int i = 0; i < nums.size(); i++){
        // 最终位置
        int target_i = inums.get(nums.get(i));
        while (target_i != i){
            int temp = nums.get(i);
            nums.set(i, nums.get(target_i));
            nums.set(target_i, temp);
            count++;
            target_i = inums.get(nums.get(i));
        }
        
    }
    return count;
}

方法二:

在原数组中,每个元素添加一个出边指向它最终的位置,这样画完出边后,最少会成一个环,最多n个环。 每一个环对应的交换次数等于元素数量-1,因此不需要交换的次数等于环数。交换次数 = n - 环数

python

def minswap(nums):
    # 排序
    snums = sorted(nums)
    # 位置数组
    inums = {snums[i]: i for i in range(len(snums))}
    count = 0
    visited = [False] * len(nums)
    # 计算环数
    for i in range(len(nums)):
        if visited[i]: continue
        j = i
        while not visited[j]:
            visited[j] = True
            j = inums[nums[j]]
        count += 1
    return len(nums) - count

3. 倒置个数

描述

有一个由N个实数构成的数组,如果一对元素A[i]和A[j]是倒序的,即i<j但是A[i]>A[j]则称它们是一个倒置,设计一个计算该数组中所有倒置数量的算法。要求算法复杂度为O(nlogn)

Solution

我们来回忆一下合并排序,合并排序的思路是首先对左半部分递归排序,再对右半部分递归排序,左右两部分有序后,合并这两部分,递归结束的条件是数组长度小于2,这时候不需要排序了。

合并的过程如下:

左半部分:L1 > L2 > L3 > L4

右半部分:R1 > R2 > R3 > R4 > R5

比较L1和R1的大小,如果L1 < R1, L1排为第一个,再比较R1和L2的大小....

在这个过程中,如果R1 < L1,那么R1与 L1...L4就组成了倒置对,因此我们可以在合并排序中统计这些倒置对。

python

def mergeSort(nums):
    if len(nums) < 2:
        return 0, nums
    count = 0
    mid = len(nums) // 2
    cl, l = mergeSort(nums[:mid])
    cr, r = mergeSort(nums[mid:])
    for i in range(len(nums)):
        if not r or l and l[0] < r[0]:
            nums[i] = l.pop(0)
        else:
            nums[i] = r.pop(0)
            count += len(l)
    return count + cl + cr, nums

def count(nums):
    return mergeSort(nums)[0]

4. 按照给定数组排序

描述

给定两个数组A1和A2,对A1进行排序,以使元素之间的相对顺序与A2中的相对顺序相同。 对于A2中不存在的元素。 最后按排序顺序附加它们。 还假定A2 中的元素数小于或等于A1 中的元素数,并且A2具有所有不同的元素。

Solution

统计A1数字出现的频次,遍历A2,按照统计频次输出对应数量的数,对于余下的数再排序后输出。

时间复杂度O(nlogn)

python

import collections
def mysort(A1, A2):
    count = collections.Counter(A1)
    res = []
    for num in A2:
        res += [num]*count[num]
        del count[num]
    for num in sorted(count):
        res += [num]*count[num]
    return res

java

public List<Long> mysort(List<Long> A1, List<Long> A2){
    Map<Long, Long> count = A1.stream().collect(Collectors.groupingBy(i -> i, Collectors.counting()));
    List<Long> res = A1.stream().filter(num -> !A2.contains(num)).collect(Collectors.toList());
    Collections.sort(res);
    int j = 0;
    for (Long num: A2){
        for (int i = 0; i<count.get(num); i++) {
            res.add(j, num);
            j += 1;
        }
    }
    return res;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,980评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,422评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,130评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,553评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,408评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,326评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,720评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,373评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,678评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,722评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,486评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,335评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,738评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,283评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,692评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,893评论 2 335

推荐阅读更多精彩内容

  • 排序算法说明 (1)排序的定义:对一序列对象根据某个关键字进行排序; 输入:n个数:a1,a2,a3,…,an 输...
    code武阅读 645评论 0 0
  • 马云说:“梦想一定要有的,万一实现了呢” 最近心情比较复杂,我找了两个词来表达“彷徨”和“迷茫”。 我仿佛有了一种...
    李水心阅读 492评论 1 4
  • 自我上小学之后,电话号码成为了基本联络介质之一。但这时候我们还没有手机,电话通常以家庭或者办公室作为单位。交换电话...
    李子李子短信阅读 779评论 1 7
  • 最近股票跌跌不休,周围好多人都说要退出这个市场,再也不碰了,交流股票的人也越来越少。正好与这炎热的天气相反啊...
    金融大宝阅读 159评论 0 0