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)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    Leetcode 349. Intersection of Two Arrays
    hdu 1016 Prime Ring Problem
    map 树木品种
    油田合并
    函数学习
    Leetcode 103. Binary Tree Zigzag Level Order Traversal
    Leetcode 102. Binary Tree Level Order Traversal
    Leetcode 101. Symmetric Tree
    poj 2524 Ubiquitous Religions(宗教信仰)
    pat 1009. 说反话 (20)
  • 原文地址:https://www.cnblogs.com/HarryVan/p/14398136.html
Copyright © 2011-2022 走看看