提前批笔试一道算法题的Java实现

题目描述

这是2021广联达校招提前批笔试算法题之一。
我们希望一个序列中的元素是各不相同的,但是理想和显示往往是有差距的。现在给出一个序列A,其中难免有相同的元素,现在提供了一种变化方式,使得经过若干次操作后一定可以得到一个元素各不相同的序列。
这个操作是这样的,令x为序列中最小的重复数字,你需要删除序列左数第一个x,并把第二个x替换为2*x。请你输出最终的序列。
例如原序列是[2,2,1,1,1],一次变换后变为[2,2,2,1],两次变换后变为[4,2,1],变换结束。

输入描述

输入第一行包含一个正整数n,表示序列的长度为n。(1<=n<=50000)
第二行有n个整数,初始序列中的元素。(1<=a_i<=10^8)

输出描述

输出包含若干个整数,即最终变换之后的结果。

算法思路

通过HashSet和HashMap实现重复元素存入集合以及元素出现次数的统计;
递归思想。

算法实现

import java.util.*;

/**
 * @author Chiaki
 */
public class Main {
    public static void main(String[] args) {
        int n = 6;
        int[] arr = {1,1,2,2,4,4};
        long s = System.currentTimeMillis();
        int[] res = getArray(n, arr);
        long e = System.currentTimeMillis();
        System.out.println("耗时:" + (e - s) + "ms");
        System.out.print("[");
        for (int i = 0; i < res.length; i++) {
            if (i < res.length - 1) {
                System.out.print(res[i] + ",");
            } else {
                System.out.print(res[i] + "]");
            }
        }
        System.out.println();
    }

    /**
     * 按规则处理数组并返回新的无重复元素的数组
     * @param n 数组长度
     * @param arr 初始数组
     * @return 无重复元素的数组
     */
    public static int[] getArray(int n, int[] arr) {
        // 递归停止条件:只有一个元素直接返回无需进行后续操作
        if (n == 1) {
            return arr;
        }
        List<Integer> list = new LinkedList<>();
        Set<Integer> set = new HashSet<>();
        Map<Integer,Integer> map = new HashMap<>(n);
        // 遍历数组
        for (int i : arr) {
            // 数组值放入链表方便操作
            list.add(i);
            // 利用HashSet判断元素重复
            // 并统计元素出现次数放入HashMap
            if (!set.add(i)) {
                int count = map.get(i);
                count++;
                map.put(i, count);
                continue;
            }
            map.put(i, 1);
        }
        // 递归停止条件:HashSet元素个数与数组长度相同
        if (set.size() == n) {
            return arr;
        }
        // 将HashSet清空用来存放重复的元素
        set.clear();
        for (Integer i : map.keySet()) {
            if (map.get(i) > 1) {
                set.add(i);
            }
        }
        // 按规则去重 迭代停止条件:HashSet为空
        while (!set.isEmpty()) {
            // 从最小的重复元素开始
            int minValue = Collections.min(set);
            // 定义计数器
            int count = 1;
            // 遍历链表
            for (int i = 0; i < list.size(); i++) {
                // 碰到重复元素的第一个时赋值为0 计数器自增
                if (list.get(i).equals(minValue) && count == 1) {
                    list.set(i, 0);
                    count++;
                }
                // 碰到重复元素的第二个时按要求赋值 计数器自增
                if (list.get(i).equals(minValue) && count == 2) {
                    list.set(i, 2 * list.get(i));
                    count++;
                }
            }
            // 操作结束后移除HashSet的当前重复元素并继续迭代
            set.remove(minValue);
        }
        // 将链表中赋值为0的元素删除
        list.removeIf(s -> s.equals(0));
        // 剩下的元素存放到数组作为结果
        int[] res = new int[list.size()];
        for (int i = 0; i < res.length; i++) {
            res[i] = list.get(i);
        }
        // 另外一种简单写法
        /*int[] res = list.stream().mapToInt(Integer::valueOf).toArray();*/
        // 递归调用
        return getArray(res.length, res);
    }
}

运行结果

耗时:33ms
[2,8,4]

原文地址:https://www.cnblogs.com/chiaki/p/13401195.html