zoukankan      html  css  js  c++  java
  • my-leetcode

    for循环热身:

    目录:

    1.计算0到100之间的oddSum 和 evenSum:

    2.循环输出1-1000之间能被5整除的数,并且每行输出3个:

    3.打印九九乘法表(j代表行数,i代表列数):

    4.119. 杨辉三角 II

    5.1. 两数之和

    6.7. 整数反转

    7.258. 各位相加

    8.206. 反转链表

    1.计算0到100之间的oddSum 和 evenSum:

        public static void main(String args[]){
            int oddSum = 0;
            int evenSum = 0;
            for(int i=0; i <=100; i++) {
                if(i%2 != 0) {
                    oddSum+=i;
                } else {
                    evenSum+=i;
                }
            }
            System.out.println("oddSum: "+oddSum);
            System.out.println("evenSum: "+evenSum);
        }

    2.循环输出1-1000之间能被5整除的数,并且每行输出3个:

        public static void main(String args[]){
            for(int i=0; i <= 1000; i++) {
                if(i%5==0) {
                    System.out.print(i+"	");
                }
                if(i%(5*3)==0) {
                    System.out.println();
                }
            }
        }

    3.打印九九乘法表(j代表行数,i代表列数):

        public static void main(String args[]){
            for(int j=1; j <= 9; j++) {
                for(int i=1; i<=j; i++) {
                    System.out.print(i+"*"+j+"="+(j*i)+"	");
                }
                System.out.println();
            }
        }

    leetcode正题开始:


    119. 杨辉三角 II

    给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 行。(在杨辉三角中,每个数是它左上方和右上方的数的和)

    说明:杨辉三角,是二项式系数在三角形中的一种几何排列。

    方法一:依据 每个数字等于上一行的左右两个数字之和,即第 nn 行的第 ii 个数等于第 n-1n1 行的第 i-1i1 个数和第 ii 个数之和。

     

     1. List C保存了杨辉三角的全部(rowIndex)行的 所有数据;List row代表了其中的某一行的数据:

    class Solution {
        public List<Integer> getRow(int rowIndex) {
            List<List<Integer>> C = new ArrayList<List<Integer>>();
            for (int i = 0; i <= rowIndex; ++i) {
                List<Integer> row = new ArrayList<Integer>();
                for (int j = 0; j <= i; ++j) {
                    if (j == 0 || j == i) {
                        row.add(1);
                    } else {
                        row.add(C.get(i - 1).get(j - 1) + C.get(i - 1).get(j));
                    }
                }
                C.add(row);
            }
            return C.get(rowIndex);
        }
    }

    2. 优化:注意到对第 i+1 行的计算仅用到了第 行的数据,因此可以使用滚动数组的思想优化空间复杂度。

    class Solution {
        public List<Integer> getRow(int rowIndex) {
            List<Integer> pre = new ArrayList<Integer>();
            for (int i = 0; i <= rowIndex; ++i) {
                List<Integer> cur = new ArrayList<Integer>();
                for (int j = 0; j <= i; ++j) {
                    if (j == 0 || j == i) {
                        cur.add(1);
                    } else {
                        cur.add(pre.get(j - 1) + pre.get(j));
                    }
                }
                pre = cur;
            }
            return pre;
        }
    }

    3. 进一步优化:能否只用一个数组呢?

    class Solution {
        public List<Integer> getRow(int rowIndex) {
            List<Integer> row = new ArrayList<Integer>();
            row.add(1);
            for (int i = 1; i <= rowIndex; ++i) {
                row.add(0);
                for (int j = i; j > 0; --j) {
                    row.set(j, row.get(j) + row.get(j - 1));
                }
            }
            return row;
        }
    }

     

    class Solution {
        public List<Integer> getRow(int rowIndex) {
            List<Integer> row = new ArrayList<Integer>();
            row.add(1);
            for (int i = 1; i <= rowIndex; ++i) {
                row.add((int) ((long) row.get(i - 1) * (rowIndex - i + 1) / i));
            }
            return row;
        }
    }


    1. 两数之和

    给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。

    方法一:暴力枚举(把所有可能情况都考虑一遍)

    class Solution {
        public int[] twoSum(int[] nums, int target) {
            int n = nums.length;
            for (int i = 0; i < n; ++i) {
                for (int j = i + 1; j < n; ++j) {
                    if (nums[i] + nums[j] == target) {
                        return new int[]{i, j};
                    }
                }
            }
            return new int[0];
        }
    }

    方法二:哈希表(HashMap实现,将依次判断为空的元素,存入hashMap,后续的判断和已传入Map中的元素进行匹配)

    class Solution {
        public int[] twoSum(int[] nums, int target) {
            Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();
            for (int i = 0; i < nums.length; ++i) {
                if (hashtable.containsKey(target - nums[i])) {
                    return new int[]{hashtable.get(target - nums[i]), i};
                }
                hashtable.put(nums[i], i);
            }
            return new int[0];
            //return null;
            //throw new IllegalArgumentException("No two sum solution");
        }
    }


    7. 整数反转

    给你一个 32 位的有符号整数 x ,返回 x 中每位上的数字反转后的结果。

    如果反转后整数超过 32 位的有符号整数的范围 [−231,  231 − 1] ,就返回 0。

    假设环境不允许存储 64 位整数(有符号或无符号)。 

    算法一:数学方法 

    反转整数的方法可以与反转字符串进行类比。

    我们想重复“弹出” x 的最后一位数字,并将它“推入”到 rev 的后面。最后,rev 将与 x 相反。

    要在没有辅助堆栈 / 数组的帮助下 “弹出” 和 “推入” 数字,我们可以使用数学方法。

    //pop operation:
    pop = x % 10;
    x /= 10;
    
    //push operation:
    temp = rev * 10 + pop;
    rev = temp;

    但是,这种方法很危险,因为当 temp=rev⋅10+pop 时会导致溢出。

    幸运的是,事先检查这个语句是否会导致溢出很容易。

    为了便于解释,我们假设 rev 是正数。

     当 rev 为负时可以应用类似的逻辑。

    class Solution {
        public int reverse(int x) {
            int rev = 0;
            while (x != 0) {
                int pop = x % 10;
                x /= 10;
                if (rev > Integer.MAX_VALUE/10 || (rev == Integer.MAX_VALUE / 10 && pop > 7)) return 0;
                if (rev < Integer.MIN_VALUE/10 || (rev == Integer.MIN_VALUE / 10 && pop < -8)) return 0;
                rev = rev * 10 + pop;
            }
            return rev;
        }
    }

    解释:

    (1) int

    • 32位、有符号的以二进制补码表示的整数

    • min : -2,147,483,648(-2^31)

    • max: 2,147,483,647(2^31 - 1)

    • default: 0

    • 对应包装类:Integer

    (2) 关于正负数取余运算相关疑问,参考:https://blog.csdn.net/u013094181/article/details/21863491

    (3) 代码分析:

    class Solution {
        public int reverse(int x) {
            int res = 0;
            while(x!=0) {
                //每次取末尾数字
                int tmp = x%10;
                //判断是否 大于 最大32位整数
                if (res>214748364 || (res==214748364 && tmp>7)) {
                    return 0;
                }
                //判断是否 小于 最小32位整数
                if (res<-214748364 || (res==-214748364 && tmp<-8)) {
                    return 0;
                }
                res = res*10 + tmp;//将得到的末尾数一次反转,扩大10倍
                x /= 10;//舍去尾数前面的数
            }
            return res;
        }
    }    


     

    算法二:字符串翻转函数

    class Solution {
        public int reverse(int x) {
        String s = new StringBuilder(String.valueOf(x)).reverse().toString();
            try {
                if(s.endsWith("-")){
                    return 0-Integer.valueOf(s.substring(0,s.length()-1));
                }else {
                    return Integer.valueOf(s);
                }
            }catch (Exception e){
                return 0;
            }
        }
    }

    说明:java的String将数字转为字符串时,如果是负数,会将符号位视作单一字符一并转换;所以在对其进行字符翻转后,需要判断是否以负号结尾,从而截取数字部分;


    258. 各位相加

    给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。

    解法一:数学上

    时间复杂度为 O(1) 的解法:

    对于任意一个非负整数num,反复将各个位上的数字相加,我们可以把这个整数各个位分开来看。比如一个数是525,那么就可以将它拆分成 500+20+5,对于此题,这个数对应的答案经过两次拆分,第一次:5+2+5=12;第二次:1+2=3。那么接下来,就将525这个数如何变成3的过程进行尝试:我们直接从最正确的方法入手。

    首先,除个位外,每一位上的值 都是通过 (9+1) 进位的过程得到的;那么我可以发现这样一个规律:

      500%9=5;//500中有50个10,也就是第一次500mod9,可以得到50;而50中,又有5个10,那么50mod9,就最后得到个位数5;

      20%9=2;//20中有2个10,那么20mod9=2;

      520%9=7;//520中有52个10,也就是第一次520mod9,即50+20;那么70mod9=7,也就是5+2;

      525%9=3;//这时,我们已经知道520的最终余数为7;那么525mod9的值就是7+5=12;同理12mod%9=3;结束。

    从以上过程,我们可以知道,任何数不断的对9取模,最终就可以得到我们想要的答案,

    • 那么按照如上的思路,似乎可以通过 n % 9 得到最后的值
    • 但是有1个关键的问题,如果 num 是 9 的倍数,那么就不适用上述逻辑。原本我是想得到 n 被打包成 10 个 1 份的份数+打不进 10 个 1 份的散落个数的和。通过与 9 取模,去获得那个不能整除的 1,作为计算份数的方式,但是如果可以被 9 整除,我就无法得到那个 1,也得不到个位上的数。
    • 所以需要做一下特殊处理,(num - 1) % 9 + 1
    • 可以这么做的原因:原本可以被完美分成 9 个为一份的 n 样物品,我故意去掉一个,那么就又可以回到上述逻辑中去得到我要的n 被打包成 10 个一份的份数+打不进 10 个一份的散落个数的和。而这个减去的 1 就相当于从,在 10 个 1 份打包的时候散落的个数中借走的,本来就不影响原来 10 个 1 份打包的份数,先拿走再放回来,都只影响散落的个数,所以没有关系。
    class Solution {
        public int addDigits(int num) {
            return (num - 1) % 9 + 1;
        }
    }

    说明:

    这道题可以 形象的看成 将num件物品,以10为单位进行分堆处理,化10倍数为个位数的操作:

    • 首先对于任意一个数,它可以第一次以10为倍数可以划分为多少块,我们不妨把每一位数分开来看,除个位外每一位数都是10的倍数,
    • 比如:521这个数,首先看最高位500,其实这个数第一次以10为单位划分等于50份,因为(10=9+1),那么用500以9为单位划分,
    • 第一次划分的余数,其实就是这个数以10位单位划分,第一次划分出来的份数,为50份;
    • 这样,就将500,以10位一个整体,变成了50,降低了进位位置,与下一级位数成为同一级别,可以进行单一位数的运算5+2,即50+20=70;
    • 同理,用70以9位单位划分,第一次划分的余数为7,那么这个7再看成以10为单位的整体,与个位上的1同级,最后7+1=8;这就最终降低成为了8份的个位数;
    • 从以上过程,我们仔细琢磨一下,它其实就是对一个数,进行除法取余数的过程:num%9的值;
    • 但是特别要注意的是,如果这个数刚好被9整除,那么余数为0,这显然不符合我们的要求;
    • 这时可以先从个位数上抽走一个数1,由以上分析,我们知道,个位数字是最后参与运算的,对分堆降级到个位数之前的运算没有任何影响,
    • 比如,990,我们先将其减1,为899:
    • 很明显990里有99个10,分成99份;99里有9个10,分成9份加个位上的9份,为18份;18里有1个10,分成1份加个位上的8份,为9份;
    • 而899里,有89个10,分成89份加个位上的9份,为98份;98里有9个10,分成9份加个位上的8份,为17份,17里有1个10,最终为8份;
    • 无论如何,我们都可以得到,num%9的值,与个位上多个1,少个1,最终的结果也会多个1和少个1,所以我们最终再加上这个1即可。

    解法二

    开始有点不明所以,直接用递归或者循环按照题目的意思写不就行了吗,先用递归尝试了一下。

    public int addDigits(int num) {
        if (num < 10) {
            return num;
        }
        int next = 0;
        while (num != 0) {
            next = next + num % 10;
            num /= 10;
        }
        return addDigits(next);
    }

    没想到直接通过了,上边的递归很简单可以直接写成迭代的形式。

    public int addDigits(int num) {
        while (num >= 10) {
            int next = 0;
            while (num != 0) {
                next = next + num % 10;
                num /= 10;
            }
            num = next;
        }
        return num;
    }

    206. 反转链表

    反转一个单链表。

    示例:

    输入: 1->2->3->4->5->NULL
    输出: 5->4->3->2->1->NULL
    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode() {}
     *     ListNode(int val) { this.val = val; }
     *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
     * }
     */

    作者:LeetCode-Solution
    链接:https://leetcode-cn.com/problems/pascals-triangle-ii/solution/yang-hui-san-jiao-ii-by-leetcode-solutio-shuk/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    Centos 8 部署harbor 访问502
    selenium学习记录
    shell基础
    抓取人民日报
    caffe在笔记本ubuntu10.04 64位下的无GPU安装
    【转】HMM
    typedef 的一些用法
    j2ee 使用tomcat开发网站需要访问中文名的资源遇到的问题解决方案。。
    解决lex.yy.c文件在vs2012下编译生成exe
    python学习
  • 原文地址:https://www.cnblogs.com/HarryVan/p/14398136.html
Copyright © 2011-2022 走看看