for循环热身:
目录:
1.计算0到100之间的oddSum 和 evenSum:
2.循环输出1-1000之间能被5整除的数,并且每行输出3个:
3.打印九九乘法表(j代表行数,i代表列数):
5.1. 两数之和
6.7. 整数反转
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,返回杨辉三角的第 k 行。(在杨辉三角中,每个数是它左上方和右上方的数的和)
说明:杨辉三角,是二项式系数在三角形中的一种几何排列。
方法一:依据 每个数字等于上一行的左右两个数字之和,即第 nn 行的第 ii 个数等于第 n-1n−1 行的第 i-1i−1 个数和第 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 行的计算仅用到了第 i 行的数据,因此可以使用滚动数组的思想优化空间复杂度。
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)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。