首页 > IT职业 > IT图书 > java算法易筋经:常见java-API使用技巧
摘要:算法练习的本质也在于锻炼编程思维,强化程序员的内力。因此给自己后面会持续更新的算法技巧内容简称算法易筋经。
本文分享自华为云社区《<java算法易筋经>之常见java-API使用》,原文作者:breakDraw 。
易筋经源于我国古代中医导引术,具有强健体魄、预防疾病的效果,长期以来在佛家及民间习武人士之间广为流传。算法练习的本质也在于锻炼编程思维,强化程序员的内力。因此给自己后面会持续更新的算法技巧内容简称算法易筋经。
无论你使用什么语言开始训练算法, 总是得掌握基本的。 我这边只以java举例,其他语言类似。以leetcode类型的平台为主。
有时候给定的输入是个数组,中间过程我们想转成list并使用list的一些api。 但是这没那么简单。
请打开自己的编译器,然后看下下面几个问题能否不用for循环写成功。(用for循环也是对的,考试时如果忘记了,就选择能用的方法)
就像下面这样,自己造个类,测试一下看能否秒写:
public class ListArrayUtil { // 请把字符串数组转list public List<String> arrToListStr(String[] arr) { return null; } // 请把字符串list转数组 public String[] listToArrStr(List<String> list) { return null; } // 请把list数组转成int[] public List<Integer> arrToListInt (List<Integer> num) { return null; } // 请把int[] 数组转成list public List<Integer> arrToListInt (int[] num) { return null; } }
有些人可能会误以为int[]和Integer[]是可以自动转的,然后对于数组而言,编译器无法用识别,会报错。因此如果涉及这种基础类型的数组列表转换,请记住要么马上使用stream,要么直接for循环写一下,不要卡在这个编译错误这研究半天。
我的答案:
public class ListArrayUtil { // 请把字符串数组转list public List<String> arrToListStr(String[] arr) { return Arrays.asList(arr); } // 请把字符串list转数组 public String[] listToArrStr(List<String> list) { return list.toArray(new String[list.size()]); } // 请把list数组转成int[] public int[] arrToListInt (List<Integer> list) { // 不可以toArray,int[]和Integer[]是不同的 //return list.toArray(new int[list.size()]); return list.stream() .mapToInt(Integer::valueOf) .toArray(); } // 请把int[] 数组转成list public List<Integer> arrToListInt (int[] num) { // 不可以asList,因为int[]和Integer[]不同 // return Arrays.<Integer>asList(num); return Arrays .stream(num) .boxed() .collect(Collectors.toList()); } }
初始化可没那么简单,尤其是涉及返回List[]作为结果时,总是有人会忘记要先初始化数组里的每个list才能使用。请完成以下内容:
正确答案如下:
public class ListUtil { // 初始化list为5个1 public static List<Integer> fillList() { List<Integer> list = Collections.nCopies(5,1); System.out.println(list); return list; } // 初始化arr为5个1 public static int[] fillArr() { int[] arr = new int[5]; Arrays.fill(arr, 1); return arr; } // 返回1个list数组,并且里面的list已经初始化完成 public static List[] fillListArray() { List[] lists = new List[5]; IntStream.rangeClosed(0, 4).boxed() .forEach(i->lists[i] = new ArrayList()); return lists; } }
关于如何快速对list和数组排序,在IDEA自己解答以下问题:
public class Student implements Comparable<Student> { private int stuId; private String stuName; private int score; @Override public int compareTo(Student o) { return stuId-o.stuId; } }
参考题目:https://leetcode-cn.com/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof/
答案:
使用getOrDefault:
map.getOrDefault(key, new ArrayList<>()).add(xxx)
图结果那边还蛮常用的
if (!map.containsKey(key)) { map.put(key, value); }
可以优化成
map.putIfAbsent(key, value)
字面意思: absent指不存在,那么就是不存在的时候,把value放入,如果存在,则直接返回原value值。
例如每次对key中的值加1
有两种方式:
map.put(key, map.getOrDefault(key, 0)+1);
map.compute(key, (k,v)->(v==null?1:v+1));
在一个比较复杂的情况下,compute比较有用。
computeIfAbsent(key, (k,v)->f(k,v)) 只在key不存在的时候,才计算这个labmda式子。 如果存在的话,就不计算了,直接返回旧值。
computeIfPresent(key, (k,v)->f(k,v)) 只有存在才会更新,不存在就不更新。
用labma写内部比较式子,避免忘记接口怎么写
PriorityQueue<int[]> queue = new PriorityQueue<>((a, b) -> a[1] - b[1]);
a[1] - b[1] 是小顶堆
a[1]-b[1] >0,则交换。
如何记忆?
堆更新的时候,都是从上往下更新的, 让
那么a是上面的点,b是下面的点(儿子节点)
当返回大于0时,交换a和b。
这样就好理解了
大顶堆: a-b<0时,需要交换,即父亲比儿子小,所以需要交换
小丁堆: a-b>0, 需要交换, 即父亲比儿子大,得换,让父亲是小顶。
不想手写二分的话用这个方法:
ceilingKey(key) 找到大于等于给定键的最小键
不存在则返回null
记忆:
ceiling向上舍入,那就是找key的上边。 ceiling有天花板的意思,于是就理解成是向上找。
floor 向下摄入,那就是找key的下边。 有沉入水下的意思,于是理解成向下。
例题:https://leetcode-cn.com/problems/previous-permutation-with-one-swap/submissions/
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/3711/viewspace-2795976/ ,如需转载,请注明出处,否则将追究法律责任。