常用 API
数组
初始化数组:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int [] nums = new int [n];int [] nums = new int []{1 ,2 ,3 ,4 };int [][] nums = new int [m][n];int [][] nums = new int [][]{{1 ,3 },{1 ,2 },{4 ,5 },{3 ,7 }};char [] cstr = new char [n];char [] cstr = new char []{'a' , 'b' , 'c' };char [] cstr = new String("abc" ).toCharArray();String[] str = new String()[n]; String[] str = new String()[]{"aaa" , "bbb" , "ccc" }; String[] str = {"aaa" , "bbb" , "ccc" };
总结:初始化时,若要通过{}
赋值,则数组的[]
内不能带数字;如果不赋值,则必须要带数字。因为使用{}
赋值时,编译器会根据赋值的数量自动算出数组长度,因此[]
内就不能加数字了。
数组操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 int [][] nums = new int [][]{{1 ,3 },{1 ,2 },{4 ,5 },{3 ,7 }};Arrays.sort(nums, (o1, o2) -> o1[0 ] - o2[0 ]); Arrays.sort(nums, (o1, o2) -> { o1[0 ] - o2[0 ] }); Arrays.sort(nums, new Comparator<int []>() { @Override public int compare (int [] a, int [] b) { if (a[0 ]==b[0 ]){ return a[1 ] - b[1 ]; }else { return a[0 ] - b[0 ]; } } }); Collections.reverse(list); Collections.sort(list, (o1, o2) -> o1 - o2); Arrays.copyOf(arr, k); char [] board = new char [n];Arrays.fill(board, '.' ); board[record[row]] = 'Q' ; int [] arr = new int [10 ];Arrays.fill(arr, 1 ); int [] ans = new int [list.size()];for (int i = 0 ; i < list.size(); i++) { ans[i] = list.get(i); } List<int []> list = new ArrayList(); int [][] ans = list.toArray(new int [list.size()][]);
字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 String s = String.valueOf(num); int n = Integer.parseInt(s);int n = Integer.valueOf(s);s.substring(a,b); char c = s.charAt(i); s = s.trim(); Character.isLetter(ch); Character.toLowerCase(ch); char [] str = s.toLowerCase(); sb.append(new String("123" )); sb.deleteCharAt(i);
集合
LinkedList中add,addLast,offer,pollLast,removeLast等区别:https://blog.csdn.net/cpppp66/article/details/115759578。
addLast()
仅仅将元素链接到队列尾部。 然而 add()
不仅将元素链接到队列尾部,还返回true。
offer()
直接调用了 add()
方法。所以在 LinkedList
中 add()
与 offer()
的使用相当于是一样的
总结:
需要链接元素到队列尾时优先用 offer()
查看元素优先使用 peek()
删除元素优先使用 poll()
特别情况:
想要在指定索引位置链接元素可以使用 add(int index, E element)
获取指定索引的元素可以使用 get(int index)
修改指定索引的元素可以使用 set(int index, E newElement)
其他:
1 2 3 4 5 6 7 Collections.reverse(list); Collections.sort(list, (o1, o2) -> o1 - o2); Arrays.copyOf(arr, k);
一些深度优先遍历问题,通常做法是创建一个全局的集合 path,其将随着递归栈的调用而被不断修改。在递归到底部满足条件进行保存结果时,注意需要另外创建一个新的集合变量,存储该 path 中的值,以防其随着递归栈的返回被修改。具体做法为:res.add(new LinkedList<Integer>(path))
代码:
1 2 3 4 5 6 7 8 9 10 List<List<Integer>> res = new LinkedList<List<Integer>>(); Deque<Integer> path = new LinkedList<Integer>(); public void dfs (TreeNode curr, int target) { if (target == 0 ) { res.add(new LinkedList<Integer>(path)); } }
哈希表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Set<Integer> set = new HashSet<>(); for (int i = 0 ; i < arr.length; i++) { set.add(arr[i]); } for (Integer cur : set) { if (set.contains(cur + k)) { res.add(Arrays.asList(cur, cur + k)); } } Map<String, Integer> map = new HashMap<>(); for (Entry<String, Integer> entry : map.entrySet()) { String str = entry.getKey(); Integer times = entry.getValue(); }
概率
1 2 3 4 5 int d = rand.nextInt(i + 1 );int d = (int )(Math.random() * 5 ) + 1 ;
运算
获取每个数字最右侧为 1 的位数、
原理:除了最低位之外,0 取反变成了 1,1 取反变成了 0,所以取与操作肯定都是 0,但最低位因为加了 1 所以会得到 1。
1 2 3 4 rightOne = n & (~n + 1 ); rightOne = n & -n;
两个整数相除向上取整
两个整数相除的向下取整为:
两个整数相除的向上取整为:
1 2 3 4 5 6 int res = (a + b - 1 ) / b;int res = (a - 1 ) / b + 1 ; int res = (a / b) + (a % b == 0 ? 0 : 1 );
这里分两种情况:
a / b
没有余数:例如 14 / 7
,则 (14 + 6) / 7
还是等于 2,此时 a 加上的 b - 1
没有带来额外的进位(这就是要减一的原因)
a / b
有余数:例如 15 / 7
,则 (15 + 6) / 7
等于 3,此时原本 15 / 7
会被省略掉的余数因为加上了 b - 1
,从而额外进了一位,因此达到了向上取整的效果。即使 15 / 7
只余下 1,也会因为加上了 b - 1
,从而多算了一个 b / b = 1
,因此多进了一位。
判断某个数字 x 是否是 n 的完全开平方
问题:判断 x 是否等于 sqrt(n)。
技巧:如果直接判断 x * x ?= n
,则可能因 x 过大而发生溢出;此时我们可以使用如下判断:
1 n % x == 0 && n / x == x
n % x == 0
保证了 n 能整除 x,否则肯定不满足 x * x == n
;其次使用 n / x == x
来防止 x * x
溢出。
int 类型范围
int 类型的范围: -2147483648 ~ 2147483647
在一些题目里,如果 n 取了 int 类型的最小值 -2147483648,则对其直接取反后,会超出 int 的最大值 2147483647,导致 -n != n
, 因此要先将 n 变成 long 类型进行操作。最后再变回 int。
例如:50. Pow(x, n) 这道题,n 如果取到最小值,这时对其反转,得到的就不是想要的值,而应该将 n 转换成 long 类型再计算。
数组的前缀和
如果要频繁的获取数组中某个区间内的累加和,则可以使用前缀和的技巧进行加速。具体方法为:
创建一个 sum[] 数组。sum[i] 代表原数组在 [0, i] 范围内的累加和。
遍历一遍整个数组,计算出 sum[] 数组每个位置上的值
这样再想计算某个区间 [L, R] 上的累加和,就只需要计算 sum[R] - sum[L-1] 即可。
或的短路原则
在需要多条路径进行递归时,可以使用 || 的短路原则 ,缩短搜索时间。例如:
1 2 boolean res = dfs(i + 1 , j, k + 1 , board, words) || dfs(i, j + 1 , k + 1 , board, words) || dfs(i - 1 , j, k + 1 , board, words) || dfs(i, j - 1 , k + 1 , board, words);
上述代码中只需要前面的某一条分支返回true,就无需再递归判断后续的其他分支,从而节省了大量时间。
摩尔投票法
剑指 Offer 39. 数组中出现次数超过一半的数字 :数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
摩尔投票法:可以类比打擂台。如果台上没人,则当前的人作为擂主,之后如果遇到己方阵营(和自己相等),则台上人数加一,如果遇到对方阵营(和自己不相等),则台上人数减一(同归于尽),最后台上剩下的阵营一定是众数(如果题目不保证一定存在众数,则在找到该数字后再遍历一遍数组判断当前数字是不是众数即可)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public int majorityElement (int [] nums) { int x = 0 ; int votes = 0 ; for (int num : nums) { if (votes == 0 ) { x = num; votes++; } else { votes += (x == num) ? 1 : -1 ; } } return x; } }
一年中的第几天
给你一个字符串 date
,按 YYYY-MM-DD
格式表示一个 现行公元纪年法 日期。请你计算并返回该日期是当年的第几天。通常情况下,我们认为 1 月 1 日是每年的第 1 天,1 月 2 日是每年的第 2 天,依此类推。每个月的天数与现行公元纪年法(格里高利历)一致。
思路:注意闰年的判断方式:闰年的判定方法为:year 是 400 的倍数,或者 year 是 4 的倍数且不是 100 的倍数 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public int dayOfYear (String date) { int year = Integer.parseInt(date.substring(0 , 4 )); int month = Integer.parseInt(date.substring(5 , 7 )); int day = Integer.parseInt(date.substring(8 )); int [] amount = {31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 }; if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0 )) { ++amount[1 ]; } int ans = 0 ; for (int i = 0 ; i < month - 1 ; ++i) { ans += amount[i]; } return ans + day; }