0
点赞
收藏
分享

微信扫一扫

LeetCode 507. 完美数 / 2022. 将一维数组转变成二维数组 / 390. 消除游戏(等差数列模拟,约瑟夫环)

蒸熟的土豆 2022-01-04 阅读 63
leetcodejava

507. 完美数

2021.12.31 每日一题,年底最后一题,祝大家新年快乐

题目描述

对于一个 正整数,如果它和除了它自身以外的所有 正因子 之和相等,我们称它为 「完美数」。

给定一个 整数 n, 如果是完美数,返回 true,否则返回 false

示例 1:

示例 2:

示例 3:

示例 4:

示例 5:

提示:

思路

class Solution {
    public boolean checkPerfectNumber(int num) {
        //相当于找因子
        if(num < 2)
            return false;
        int range = (int)Math.sqrt(num);
        int res = 1;
        for(int i = 2; i <= range; i++){
            if(num % i == 0){
                res += i + num / i;
            }
        }
        return num == res;
    }
}

2022. 将一维数组转变成二维数组

2022.1.1 每日一题 新年快乐啊!!!!!

题目描述

给你一个下标从 0 开始的一维整数数组 original 和两个整数 m 和 n 。你需要使用 original 中 所有 元素创建一个 m 行 n 列的二维数组。

original 中下标从 0 到 n - 1 (都 包含 )的元素构成二维数组的第一行,下标从 n 到 2 * n - 1 (都 包含 )的元素构成二维数组的第二行,依此类推。

请你根据上述过程返回一个 m x n 的二维数组。如果无法构成这样的二维数组,请你返回一个空的二维数组。

示例 1:

示例 2:

示例 3:

示例 4:

提示:

思路

class Solution {
    public int[][] construct2DArray(int[] original, int m, int n) {
        //2022年第一道题是2022题
        int l = original.length;
        if(l != m * n)
            return new int[][]{};
        int[][] ans = new int[m][n];
        int idx = 0;
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                ans[i][j] = original[idx++];
            }
        }
        return ans;
    }
}

390. 消除游戏

2022.1.2 每日一题

题目描述

列表 arr 由在范围 [1, n] 中的所有整数组成,并按严格递增排序。请你对 arr 应用下述算法:

从左到右,删除第一个数字,然后每隔一个数字删除一个,直到到达列表末尾。
重复上面的步骤,但这次是从右到左。也就是,删除最右侧的数字,然后剩下的数字每隔一个删除一个。
不断重复这两步,从左到右和从右到左交替进行,直到只剩下一个数字。
给你整数 n ,返回 arr 最后剩下的数字。

示例 1:

示例 2:

提示:

思路

这个等差数列的好理解

class Solution {
    public int lastRemaining(int n) {
        //先删除1 3 5 7 9
        //找了下规律,先删除2倍的,再四倍的,再8倍
        //刚开始是奇数删掉,然后看从哪个数字开始,每隔4删除一次,然后是每隔8
        //所以记录左右的起始位置就可以了

        //然后发现不会记,总感觉会漏掉值
        //然后看了题解,发现只需要统计左边第一个数就行了
        int left = 1;
        int base = 1;
        int k = 0;
        int count = n;
        
        while(count > 1){
            //从左到右删除,那么删除以后,最左边的数就是第二个数
            if(k % 2 == 0){
                left = left + base;
            }else{
                //如果当前数目是偶数,那么左边不会删除;如果是奇数,那么左边会删除,而下一个位置也是加base
                if(count % 2 == 1){
                    left = left + base;
                }
            }
            base <<= 1;
            count >>= 1;
            k++;
        }
        return left;
    }
}

约瑟夫环公式推导问题
从左到右删除,剩下的数定义为a,f[i]
从右到左删除,剩下的数定义为b, g[i]
总数为i,那么a + b = n + 1,f[i] + g[i] = i + 1

然后和约瑟夫环一样,刚开始删除奇数,也就是1 3 5 7…得到了f[i]
此时,剩下g[i/2],同时f[i] = 2 * g[i / 2]
代入上面的第一个公式,得到f[i] = 2 * (i / 2 + 1 - f[i / 2] )

然后就可以使用递归的思想,得到最后的结果
挺难的,不好想

class Solution {
    public int lastRemaining(int n) {
        return n == 1 ? 1 : 2 * (n / 2 + 1 - lastRemaining(n / 2));
    }
}
举报

相关推荐

0 条评论