算法篇——例题偶数变奇数

245 阅读3分钟

内容五

image-20201028112040047

分析:一次只能选一个数。

1.找到所有值相等的偶数

2.找到所有偶数

3.如果只是需要输出次数的话,可以倒入集合里去除重复元素,减少数字的数量,然后找到所有偶数,算出每个偶数变成奇数所需要的次数相加就行。

4.奇数,二进制最后一位是1;偶数二进制最后一位是0,看这个偶数(二进制形式)左移多少位最后一位能变成1就行。

按以上的思路测试出来的结果不对。

因为,每移位一次得到的结果都可能变成一个与集合里重复的偶数。

所以每移动一次都要更新一次集合。

经过又一轮测试之后,发现要从最大偶数的开始变成除2,才能保证最小次数。

思路:

第一次输入时判断是否为偶数,不是偶数则丢弃,是则放入集合中

集合里都是偶数并且没有重复,我们每次取出集合里的最大的数,进行左移一位,如果还是偶数,删除原来的数并将新的移位好的数写入集合(写入的时候集合会自动去重) 如果移位后变成奇数就直接从集合里删除这个数

import java.util.HashSet;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

/**
 * @author SJ
 * @date 2020/10/28
 */
public class EvenToOdd {
    public static Set<Integer> nums;//用于存放输入的数字

    public EvenToOdd(int length) {
        nums = new HashSet<>();
        Scanner scanner = new Scanner(System.in);
        for (int i = 0; i < length; i++) {
            int temp = scanner.nextInt();
            //判断一下,是奇数的话就没有必要往集合里放了。
            if (isEven(temp))
                nums.add(temp);
        }
    }

    public static int evenToOdd() {
        int times = 0;
/*        Iterator<Integer> iterator = nums.iterator();
        if (iterator.hasNext()) {
            Integer num = iterator.next();
            if (isEven(num)) {
                //二进制字符串,从后往前找第一个位置为1的地方
                String string = Integer.toBinaryString(num);
                char[] chars = string.toCharArray();
                for (int i = chars.length - 2; i >= 0; i--) {
                    if (chars[i] == '1') {
                        int time = chars.length - 1 - 1;
                        num =<<time;
                        break;
                    }

                }
            }
        }*/

        //此时集合里都是偶数并且没有重复,我们每次取出集合里的最大的数,进行左移一位,如果还是偶数,删除原来的数并将
        //新的移位好的数写入集合(写入的时候集合会自动去重)
        //如果移位后变成奇数就直接从集合里删除这个数
        while (nums.size() != 0) {
            int temp = 0;

            Iterator<Integer> iterator1 = nums.iterator();
            int max = findMax(nums);
            while (iterator1.hasNext()) {
                Integer theNum = iterator1.next();
                //找到最大值后
                if (theNum == max) {
                    temp = theNum >> 1;
                    iterator1.remove();
                    times++;


                }


            }
            if (isEven(temp) && temp != 0)
                nums.add(temp);
        }


        return times;
    }

    //判断是否为偶数
    public static Boolean isEven(Integer a) {
        if (a % 2 == 0)
            return true;
        return false;
    }

    //找出集合中的最大值
    public static int findMax(Set<Integer> set) {
        int max = Integer.MIN_VALUE;
        for (Integer integer : set) {
            if (integer > max)
                max = integer;
        }
        return max;

    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int i = scanner.nextInt();
        new EvenToOdd(i);
        int i1 = evenToOdd();
        System.out.println("需要的次数为:" + i1);

    }
}

测试:

"C:\Program Files\Java\jdk1.8.0_131\bin\java.exe"...
6
40 6 40 3 20 1
需要的次数为:4

Process finished with exit code 0

算法分析:时间主要花在:遍历集合寻找最大值上,不过好在集合里都是偶数且没有重复数字。时间取决于输入的序列里偶数的个数。

假设结果是最小需要n次的话,那么需要遍历2*n次集合(第一遍用于找最大值,第二遍用于匹配到最大值然后进行删除或者更新操作)

集合没有下标进行定位,所以必须得遍历两遍,这也算是一个缺点吧,但是它去重的功能可以大大减少我们的工作量,总的来说我觉得是好处大于坏处的。