leetcode 技巧点、常用方法、容易忘知识点总结

常用 API

map的相关操作:

1.将 values 转化为 list 和数组

    Collection valueCollection = map.values();  

    final int size = valueCollection.size();  

    List valueList = new ArrayList(valueCollection);

    String[] valueArray = new String[size];

    map.values().toArray(valueArray);  //注意数组和 List 的类型必须相同,如List不能转 int[],只能转 Integer[]

Integer[] intArr =  list.toArray(new Integer[list.size()]);

StringBuilder

sb.deleteCharAt(sb.length()-1);

String

s.trim() //去除首尾空格

s.split("\\s+");  //正则表达式匹配多个空格

String.join(" ",list);

// 除去开头和末尾的空白字符
        s = s.trim();
        // 正则匹配连续的空白字符作为分隔符分割
        List wordList = Arrays.asList(s.split("\\s+"));
        Collections.reverse(wordList);
        return String.join(" ", wordList);

String.compareTo()//如果两个字符的ASC码相等则继续后续比较,否则直接返回两个ASC的差值。如果两个字符串完全一样,则返回0

        "abcd".compareTo("adef")== -2

       "abc".compareTo("abcdef")== -3

       "abc".compareTo("abc") == 0

List 相关操作

之前一直只用过 Arrays.sort(nums,comp)对数组排序。这次做45题(要先将 int[]数组转为 Integer[],才能用 Arrays.sort)发现:(1)可以将 int[]转为 List ,直接用 Collections.sort(list,comp) (2)不需要重写 comparator,可以使用 java8提供的 lamda 新特性

Arrays 相关操作

1、Arrays.sort对数组排序,重写 comparator

Comparator com=new Comparator(){

            @Override

            public int compare(int[] a,int b[]){

                return a[0]-b[0];   //如果想让前面的数字比后面的数字小,就返回负的

            }

        };

Arrays.sort(intervals,com);

使用lamda 表达式: Arrays.sort(intervals,(a,b)->(a-b))


或者直接写成:Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);

Arrays.sort()中 Comparator对象的范型不能为 int,只能为 Integer,也就是只能在对 Integer数组排序时,重写 Comparator或者 lamda 表达式

2、int[] 数组无法直接用 Arrays.asList转换成 List, 因为Arrays.asList 传入的对象必须是对象数组(Integer[]数组)

(1)java8以及以上版本可以使用:List list1 = Arrays.stream(array).boxed().collect(Collectors.toList());

(2)导入apache commons-lang3  jar : List list = Arrays.asList(ArrayUtils.toObject(array));

3、int[] 没办法用 Arrays.asList直接转换为 List,而又要将 r add 到List> result中,可以直接将 r 保存在 List 中,利用 Collections.swap(list,i,j) 对 list 的两元素进行交换,然后利用 result.add(new LinkedList(list))

 List> result=new LinkedList>();

LinkedList l=new LinkedList<>();

result.add(new LinkedList(l);

Collections.swap(l,index,j);     //要用 swap 操作的,用ArrayList!!!!(性能提升)

4、List可以直接转 int[][]

List results;

results.toArray(new int[results.size()][]);

5、对于要求返回 int[]数组,而数组大小未知的情况。之前是使用 List 先动态保存结果,后面再进行转换(List转 int[]不能用 .toArray,只能用 for 循环)。可以先声明一个大范围数组,然后使用 Arrays.copyOfRange(数组地址,首,尾+1)来进行数组的拷贝(性能会提升很多),如下面的(349题)时间从39/6%到99/27%。

class Solution {
    //Arrays.copyOfRange(intersection, 0, index);从大数组中截取小数组(代替 List 转 int[]),性能提高两倍
    public int[] intersection(int[] nums1, int[] nums2) {
        
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        //Set<Integer> result=new HashSet<>();
        int[] bigResult=new int[nums2.length+nums1.length];
        int i=0,j=0;
        int index=0;
        while(i<nums1.length&&j<nums2.length){
            if(nums1[i]==nums2[j]){
                if(index==0||bigResult[index-1]!=nums1[i]){
                    bigResult[index]=nums1[i];
                    index++;
                }
                //result.add(nums1[i]);
                i++;
                j++;
            }else if(nums1[i]<nums2[j]){
                i++;
            }else{
                j++;
            }
        }
        /*
        int[] r=new int[result.size()];
        Iterator<Integer> it=result.iterator();
        int k=0;
        while(it.hasNext()){
            r[k]=it.next();
            k++;
        }
        return r;
        */
        return Arrays.copyOfRange(bigResult,0,index);
    }
}


PriorityQueue

Queue<Integer> queue = new PriorityQueue<>(7, compare);

//匿名Comparator实现
Comparator<Integer> compare = new Comparator<Integer>(){
 
        @Override
        public int compare(Integer c1, Integer c2) {
            return (int) (c1 - c2);
        }
};


 


技巧点(节省时间、空间):

1.while(size--)在层序遍历中的应用

层序遍历时不要用两个队列来回替换,用 size,节省空间

199. 二叉树的右视图

https://leetcode-cn.com/problems/binary-tree-right-side-view/

2.利用位移表示 int 的左右范围(int 4字节,32位:1位表示正负,31位表示数字)

(1)最小值:1<<31,-2147483648  

(2)最大值:(1<<31)-1 ,2147483647  注意:(1<<31一定要加括号——1<<31-1 表示1<<30,1073741824)

3、需要对 list 调用 get(i)、swap等访问方法时,应该使用 ArrayList 取代 LinkedList

性能会提升很多(如leetcode 207:使用ArrayList,而不是 LinkedList(性能从10%提升到98%。。。。))

4、字符串相加保持代码简洁的方法:67.二进制求和

class Solution {
    //代码简洁:
    //关键1:可以通过 sum 分段加以及 aI--的形式,使得代码变得简洁(原始冗长代码:(1)如果没有 a b 置换保证 a 指向更长的字符串的话,需要三个循环体;(2)如果保证 a 指向更长的字符串的话,需要两个循环体)
    //关键2:在修改 flag 时,可以直接利用除法/2 ,如果 sum>=2则 sum/2肯定为1,反之为0
    public String addBinary(String a, String b) {
        //a 更长
        // if(a.length()<b.length()){
        //     String temp=a;
        //     a=b;
        //     b=temp;
        // }
        int aI=a.length()-1;
        int bI=b.length()-1;
        int cI=0;
        StringBuilder sb=new StringBuilder();
        int flag=0;
        while(aI>=0||bI>=0){
            int sum=flag;
            if(aI>=0) sum+=a.charAt(aI--)-'0';
            if(bI>=0) sum+=b.charAt(bI--)-'0';
            //ca = sum / 2;

            /*
            if(sum>=2){
                flag=1;
            }else{
                flag=0;
            }
            */
            //关键2:简化代码
            flag=sum/2;

            sb.append(sum%2);
        }
        if(flag==1) sb.append(1);
        return sb.reverse().toString();
        
    }




}

栈的创建

不要使用Stack s=new Stack(); 原因:Stack 类实现了 Vector 接口,Vector底层 是一个 Object 数组,在进行 stack.push 和 pop 时需要进行扩容、数组复制等操作,效率低下。

可以直接声明 LinkedList stack=new LinkedList<>(); 能够直接调用栈的 push 和 pop 操作。

LinkedList push 源码:

    public void push(E e) {
        addFirst(e);
    }

    public void addFirst(E e) {
        linkFirst(e);
    }

    private void linkFirst(E e) {
        final Node<E> f = first;
        final Node<E> newNode = new Node<>(null, e, f);
        first = newNode;
        if (f == null)
            last = newNode;
        else
            f.prev = newNode;
        size++;
        modCount++;
    }
    

pop 源码:

public E pop() {
        return removeFirst();
    }

    public E removeFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return unlinkFirst(f);
    }

    private E unlinkFirst(Node<E> f) {
        // assert f == first && f != null;
        final E element = f.item;
        final Node<E> next = f.next;
        f.item = null;
        f.next = null; // help GC
        first = next;
        if (next == null)
            last = null;
        else
            next.prev = null;
        size--;
        modCount++;
        return element;
    }


易错点(bug)

1、回溯算法没有回置

回溯算法必须将回溯部分置为原始值(即使下一个值会覆盖),因为有可能在更高的回溯的时候,逻辑要判断当前的值是否为某个符号(如'.'),如果在之前曾经把点变成数字,二没有抹除的话,在回溯后重新递归到这里的时候,会因为逻辑判断而略过对该位置的赋值

2、双层循环只记得对内层 break(逻辑为双层都 要break )leetcode-556题

class Solution {
    public void swap(char[] cs,int i,int j){
        char temp=cs[i];
        cs[i]=cs[j];
        cs[j]=temp;
    }
    public int nextGreaterElement(int n) {
        //     596875
        //4632 597865    //4632 7896
        //4632 6879
        //4632 6789
        //4632 7689
        int[] numIndex=new int[10];
        
        char[] cs=String.valueOf(n).toCharArray();
        for(int i=0;i<cs.length;i++){
            numIndex[cs[i]-'0']=i;
        }
        int k=-1;
        for(int i=cs.length-2;i>=0;i--){
            for(int num=cs[i]-'0'+1;num<=9;num++){
                if(numIndex[num]>i){
                    swap(cs,i,numIndex[num]);
                    k=i;
                    break;
                }
            }
            if(k!=-1) break;  //bug:忘写这一句了。双层循环只对内层 break,外层继续运行
        }
        if(k==-1) return -1;
        //对 k 之后的 reverse
        int result=0;
        int MAX_VALUE=(1<<31)-1;
        for(int i=0;i<=k;i++){
            if(result>(MAX_VALUE/10)||result==(MAX_VALUE/10)&&cs[i]-'0'>7){
                return -1;
            }
            result=result*10+cs[i]-'0';
        }

        for(int i=cs.length-1;i>k;i--){
            if(result>(MAX_VALUE/10)||result==(MAX_VALUE/10)&&cs[i]-'0'>7){
                return -1;
            }
            result=result*10+cs[i]-'0';
        }


        return result;
        

    }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一些常用的函数和数据结构在LeetCode刷题中的应用示例: 1. 栈(Stack):栈是一种后进先出(LIFO)的数据结构,常用于解决与括号匹配、逆波兰表达式等问题。 ```java import java.util.Stack; Stack<Integer> stack = new Stack<>(); stack.push(1); // 入栈 stack.push(2); stack.push(3); int top = stack.peek(); // 获取栈顶元素,但不删除 int pop = stack.pop(); // 弹出栈顶元素 boolean isEmpty = stack.isEmpty(); // 判断栈是否为空 ``` 2. 队列(Queue):队列是一种先进先出(FIFO)的数据结构,常用于解决与广度优先搜索(BFS)相关的问题。 ```java import java.util.Queue; import java.util.LinkedList; Queue<Integer> queue = new LinkedList<>(); queue.offer(1); // 入队 queue.offer(2); queue.offer(3); int front = queue.peek(); // 获取队首元素,但不删除 int poll = queue.poll(); // 弹出队首元素 boolean isEmpty = queue.isEmpty(); // 判断队列是否为空 ``` 3. 堆(Heap):堆是一种特殊的树形数据结构,常用于解决与优先队列相关的问题。 ```java import java.util.PriorityQueue; PriorityQueue<Integer> minHeap = new PriorityQueue<>(); // 小顶堆 minHeap.offer(3); // 入堆 minHeap.offer(1); minHeap.offer(2); int min = minHeap.peek(); // 获取堆顶元素,但不删除 int pollMin = minHeap.poll(); // 弹出堆顶元素 boolean isEmpty = minHeap.isEmpty(); // 判断堆是否为空 ``` 4. 位运算(Bit Manipulation):位运算是对二进制数进行操作的技术,常用于解决与位操作相关的问题,如位与、位或、位异或等。 ```java int a = 5; // 二进制表示为 101 int b = 3; // 二进制表示为 011 int andResult = a & b; // 位与运算,结果为 001,即 1 int orResult = a | b; // 位或运算,结果为 111,即 7 int xorResult = a ^ b; // 位异或运算,结果为 110,即 6 int complement = ~a; // 取反运算,结果为 11111111111111111111111111111010,即 -6 int leftShift = a << 1; // 左移运算,结果为 1010,即 10 int rightShift = a >> 1; // 右移运算,结果为 10,即 2 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值