Leetcode总结之数字操作 & 数组操作

  1. 数字操作
  2. 数组操作

1. 数字操作

1.1 题目分类以及常用的函数

类别:

  1. 遍历各位求和,或者反转求和的,这里一般会用到int的最大值和最小值,int的取值范围是从-2147483648 至2147483647
  2. 根据数学规律得出答案的

常用的函数:

  1. 判断一个char是不是数字
boolean Character.isDigit(char c);
  1. Character与数字进行转化的两种方法
char c;
int num = c- '0';

int num = Character.getNumericValue(c);

1.2 Leetcode实例

q7 整数反转

    /**
     * 反转数字:
     * 就是不停的取模取余运算,把得到的余数在每次循环中*10再加上新的余数
     * 在求算过程中要保证结果范围在Integer的大小范围内
     *
     * int的取值范围是从-2147483648 至2147483647
     * @param x
     * @return
     */
    public int reverseTwo(int x){
        int res = 0;

        while (x != 0){
            int residue = x % 10;
            x = x/10;
            //超过最大值的范围
            if (res > Integer.MAX_VALUE/10 ||(res == Integer.MAX_VALUE / 10 && residue > 7)) return 0;
            //超过最小值的范围
            if (res < Integer.MIN_VALUE/10 || (res == Integer.MIN_VALUE / 10 && residue < -8)) return 0;

            res = res*10 + residue;
        }

        return res;
    }

q8 字符串转换整数

    /**
     * 这题其实也在计算数字的大小, 需要把逻辑理清楚
     * 1. 首先把字符串的前面的空格都去掉
     * 2. 根据首字符判断该数字是正数,负数还是不是数字需要返回0, 并且更新初始标识位
     * 3. 判断好之后往后遍历得到数字结果,判断数字是否超过范围,如果超过范围返回0,若没有返回正常结果
     * @param str
     * @return
     */
    public static int myAtoiTwo(String str){
        //删除字符串首尾的空白字符
        str = str.trim();
        if (str.length() == 0) return 0;

        char[] chars = str.toCharArray();
        boolean positive = true;
        int i =0;
        if (chars[i] == '+'){
            i++;
        }else if (chars[i] == '-'){
            i++;
            positive = false;
        }else if (!Character.isDigit(chars[i])){
            return 0;
        }

        int res = 0;
        while (i<chars.length && Character.isDigit(chars[i])){
            int cur = chars[i]-'0';
            if (positive){
                if (res > Integer.MAX_VALUE/10 ||(res == Integer.MAX_VALUE / 10 && cur > 7))
                    return Integer.MAX_VALUE;
            }else {
                if (res > Integer.MAX_VALUE/10 || (res == Integer.MAX_VALUE / 10 && cur > 8))
                    return Integer.MIN_VALUE;
            }

            res = res*10+cur;
            i++;
        }

       return positive?res:-res;
    }

q9 回文数

    /**
     * 使用数字类型的解题思路:
     * 反转一半数字,然后两部分比较大小
     * 这里的重点是: 判断是否是反转了一半是用原本数字和新生成的数字比较大小,新生成的数字大于等于原本数字说明已经到了合适的位置
     * @param x
     * @return
     */
    public boolean isPalindromeTwo(int x) {

        if (x<0 ||(x%10==0 && x>0)) return false;

        int reverse = 0;
        while (reverse<x){
            reverse = reverse*10 + x%10;
            x = x/10;
        }

        return reverse == x || reverse/10 == x;
    }

q43 字符串相乘

    /**
     * 两数字做乘法的逻辑思路:
     * 两数字乘法结果的长度不会超过两个数字长度之和,所以用一个数组长度为两个数字长度之和的数组存储结果
     * 然后就是考虑做乘法的规律,我们是一个数字的一位一位与另一个数字的所有位做乘法,这就需要使用双层循环
     *
     * 内层循环
     * 然后就是每一位乘法结果应该是 (当前位置已经存储的结果 + 当前的两个位数的乘法结果 + carry) % 10 的值,
     * 同理新一位的carry值是(当前位置已经存储的结果 + 当前的两个位数的乘法结果 + carry) / 10 的值
     *
     * 计算过一遍内层循环后就需要把最后一个carry放到外层数组指定的位置上
     * 计算新的一波内层循环的时候carry需要归零进行计算
     *
     * @param num1
     * @param num2
     * @return
     */
    public String multiplyTwo(String num1, String num2) {
        if (num1.length() == 0 || num2.length() == 0) return "0";

        int[] res = new int[num1.length()+num2.length()];
        int carry;
        for (int i=num1.length()-1;i>=0;i--){
            carry = 0;
            for (int j= num2.length()-1;j>=0;j--){
                int n1 = Character.getNumericValue(num1.charAt(i));
                int n2 = Character.getNumericValue(num2.charAt(j));

                int mul = res[i+j+1] + (n1*n2) + carry;
                res[i+j+1] = mul%10;
                carry = mul/10;
            }
            res[i] = carry;
        }

        StringBuilder stringBuilder = new StringBuilder();
        int k=0;
        while (k<res.length){
            if (res[k]>0){
                break;
            }
            k++;
        }

        for (;k<res.length;k++){
            stringBuilder.append(res[k]);
        }

        return stringBuilder.toString().length() > 0 ? stringBuilder.toString() : "0" ;

    }

q172 阶乘后的零

    /**
     * 这道题有点考数学知识
     * 形成尾部的0的条件是5*某个偶数,或者是5^n乘以2^n可以形成n个零
     * @param n
     * @return
     */
    public int trailingZeroesTwo(int n) {
        int res = 0;
        while (n/5 != 0){
            res += n/5;
            n = n/5;
        }
        return res;
    }

以上题目的其他解题思路请参考: //www.greatytc.com/p/3fef17a62af4

2. 数组操作

2.1 做题思路

类别:

  1. 二维数组
    二维数组的重点在于二维数组的遍历,例如根据遍历时索引坐标的变化得到结果,或者遍历数组判断哪里有零就利用第一行第一列对应的位置进行标记。

  2. 一维数组
    一维数组的题通常有另一个数组或者等长的String做辅助来得到结果。

想要记录的函数

  1. 把Integer转换成二进制字符串
 String bitmap = Integer.toBinaryString(i).substring(1);

2.2 Leetcode实例

q54 螺旋矩阵

    /**
     * 这道题中重点在于遍历矩阵,其位置变化是有规律的
     * 先是最外圈的顺时针,固定四个节点的坐标值
     * 注意点:存在四个循环的前提是至少两行两列,不然的话就是一个循环
     * 一次循环之后更新四个坐标值
     * @param matrix
     * @return
     */
    public List<Integer> spiralOrderTwo(int[][] matrix) {
        List<Integer> res = new ArrayList<>();
        if (matrix.length == 0)
            return res;
        int rl = 0, rh = matrix.length-1;
        int cl = 0, ch = matrix[0].length-1;
        while (rl<=rh && cl<=ch){
            for (int c=cl;c<=ch;c++) res.add(matrix[rl][c]);
            for (int r=rl+1;r<=rh;r++) res.add(matrix[r][ch]);
            if (rl<rh && cl<ch){
                for (int c = ch-1;c> cl; c--) res.add(matrix[rh][c]);
                for (int r= rh;r > rl;r--) res.add(matrix[r][cl]);
            }
            rl++;
            rh--;
            cl++;
            ch--;
        }
        return res;
    }

q73 矩阵置零

    /**
     * 想用第一行第一列记录需要置零的元素,但是matrix[0][0]处元素的0需要特殊处理
     * matrix[0][0]在一次遍历时候只能用来记录第0行或者第0列是否是0
     * 所以没有被标识的行或者列需要其他标识来表示
     * @param matrix
     */
    public void setZeroesTwo(int[][] matrix) {
        boolean isCol = false;
        int R = matrix.length;
        int C = matrix[0].length;

        //用matrix的第一行和第一列标识当前行列是否有0,用isCol标识第一列是否有0元素
        for (int i=0;i<R;i++){
            if (matrix[i][0] == 0){
                isCol = true;
            }

            for (int j=1;j<C;j++){
                if (matrix[i][j] == 0){
                    matrix[i][0] = 0;
                    matrix[0][j] = 0;
                }
            }
        }

        for (int i=1;i<R;i++){
            for (int j=1;j<C;j++){
                if (matrix[i][0] == 0 || matrix[0][j] == 0){
                    matrix[i][j] = 0;
                }
            }
        }

        if (matrix[0][0] == 0){
            for (int j = 0; j < C; j++) {
                matrix[0][j] = 0;
            }
        }

        if (isCol) {
            for (int i = 0; i < R; i++) {
                matrix[i][0] = 0;
            }
        }
    }

q78 子集

    /**
     * 生成和nums长度一样的字符串是从0..00 到 1..11,来辅助得到答案
     * 
     * 使用与运算来计算结果
     * 生成和bitmask和字符串的长度一样,是从0..00 到 1..11
     * 如果是1就加上这个字母,如果不是就不加
     */
    public List<List<Integer>> subsetsTwo(int[] nums){
        List<List<Integer>> res = new ArrayList<>();
        int n = nums.length;
        for (int i=(int)Math.pow(2,n);i<(int)Math.pow(2,n+1);i++){
            //generate bitmask, from 0..00 to 1..11
            //toBinaryString 是将整数转化成二进制字符串
            String bitmap = Integer.toBinaryString(i).substring(1);

            List<Integer> curr = new ArrayList<>();
            for (int j=0;j<n;j++){
                if (bitmap.charAt(j)=='1') curr.add(nums[j]);
            }

            res.add(curr);
        }
        return res;
    }

q581 最短无序连续子数组

    /**
     * 这道题的辅助是已经有序的数组,通过有序数组和当前这个无序数组进行比较,得到最左边无序的位置和最右边无序的位置
     * 从而得到结果
     * 
     * 目标是找到无序的子集,这段数据排序之后整个数组就有序了
     * 所以重点就是找到有序数组和当前这个无序数组之中最左边无序的位置和最右边无序的位置
     * 最简单的找到这两个无序的位置的思路是将原数组排序,遍历两个数组,看在最左边和最右边不一致的位置分别在哪
     * @param nums
     * @return
     */
    public int findUnsortedSubarrayTwo(int[] nums) {
        //使用clone的方式复制数组
        int[] initial = nums.clone();
        Arrays.sort(initial);
        int res =0;
        int start=nums.length, end = 0;
        for (int i=0;i<nums.length;i++){
            if (initial[i]!=nums[i]){
                start = Math.min(start,i);
                end = Math.max(end,i);
            }
        }
        return (end-start>=0 ? end-start+1 : 0);
    }

另外两种找到最左端和最右端无序的位置的方法是:

  1. 基于排序,两个节点位置需要交换说明那两个节点都是处于无序的位置。
  2. 基于栈,从左往右遍历找到最左边正确的边界,然后从右往左遍历找到最右边正确的边界。

q945 使数组唯一的最小增量

    /**
     * 因为0 <= A.length <= 40000,因此可以尝试用一个长度够长的数组做辅助,
     * 这个数组只能有0到1个元素,所以就是一个平坑填坑的过程
     *
     * 1. 首先先统计数组A在辅助数组的频率
     * 2. 从左往右遍历,如果数组中元素大于1,就是都拿出来,所以res做相应的减法
     * 3. 然后往后找到没有元素的坑了把元素加入进去,res加上相应的值
     * @param A
     * @return
     */
    public int minIncrementForUniqueTwo(int[] A) {
        int[] dirc = new int[100000];
        int res = 0, token = 0;
        for (int a:A){
            dirc[a]++;
        }

        for (int i=0;i<dirc.length;i++){
            if (dirc[i]>1){
                token += dirc[i]-1;
                res -= i*(dirc[i]-1);
            } else if (token>0 && dirc[i]==0){
                res += i;
                token--;
            }
        }
        return res;
    }

以上题目的其他解题思路请参考://www.greatytc.com/p/dae13c793792

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