算法刷题细节点总结

1. 关于集合

(1) 关于map

 遍历maphttps://www.cnblogs.com/imzhj/p/5981665.html

 感觉最好记的方法是这个:

Map<String, String> map = new HashMap<String, String>();
for (Entry<String, String> entry : map.entrySet()) {
    entry.getKey();
    entry.getValue();
}

关于get方法的一个注意点:

if (!map.containsKey(keyStr)) map.put(keyStr, new ArrayList<String>());
 map.get(keyStr).add(s);  // map的get返回的不是一个副本,而是引用,所以直接修改就好,不需要修改后再put。对于基本类型是不可以这么做的

(2) set集合的增删改元素方法和List集合是一样的吗?remove方法的一个疑问

 一样的,都是 add 和 remove 方法,只不过list的remove方法能按照index来删,而set只能按照Object来删。这里有一个长久以来的疑问是如果List集合中放入的是int型元素的话,如果此时使用remove方法,传入int的 话是按照索引来删除元素还是按照int的值来删除元素的呢?

测试结果是还是按照索引来删,如果使用 (Integer)3 这种方式将int包装为Integer的话就会按照值去删。

(3) set和list集合怎么和数组互转?

参考: https://blog.csdn.net/my_precious/article/details/53010232

(4) 关于PriorityQueue的用法

首先要明白的是这个数据结构的特点,这个数据结构使得我们在往队列中加入元素时,虽然是乱序加入,但是队列中始终能够以某种优先级排列队列中的元素。 要注意一点的是

并非像TreeMap一样完全有序,但是如果按照指定方式出队,结果可以是有序的。意思是不能保证队列是有序的,但是可以保证每次出队列出的是最小或最大的元素,这样以此出队才能保证有序

此队列的 是按指定排序方式确定的最小 元素。如果多个元素都是最小值,则头是其中一个元素——选择方法是任意的。队列获取操作 pollremovepeek 和 element访问处于队列头的元素。

注意,此实现不是同步的。如果多个线程中的任意线程修改了队列,则这些线程不应同时访问 PriorityQueue 实例。相反,请使用线程安全的 PriorityBlockingQueue 类。

实现注意事项:此实现为排队和出队方法(offerpollremove() 和 add)提供 O(log(n)) 时间;为 remove(Object) 和 contains(Object) 方法提供线性时间;为获取方法(peekelement 和 size)提供固定时间。

代码示例

public class PriorityQueueTest {
    public static void main(String[] args) {
                
        final PriorityQueue<Student> queue=new PriorityQueue<>();

        Student p1=new Student(95,"张三");
        Student p2=new Student(89,"李四");
        Student p3=new Student(89,"李四");
        Student p4=new Student(67,"王五");
        Student p5=new Student(92,"赵六");
        queue.add(p1);
        queue.add(p2);
        queue.add(p3);//add 和offer效果一样。
        queue.offer(p4);//add 方法实现,其实就是调用了offer
        queue.offer(p5)

        for (Student Student : queue) {
            System.out.println(Student.toString());
        }
        
        System.out.println("---------------------");
        while(!queue.isEmpty()){
            System.out.println(queue.poll());
        }       
    }

}
class Student implements Comparable{
    private int score;
    private String name;
    
    public Student(int age,String name){
        this.score=age;
        this.name=name;
    }
    public int getScore() {
        return score;
    }
    public void setScore(int score) {
        this.score = score;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String toString(){
        return "姓名:"+name+"-"+score+"分";
    }

    @Override
    public int compareTo(Object o) {
        Student current=(Student)o;
        if(current.getScore()>this.score){
            return 1;
        }else if(current.getScore()==this.score){
            return 0;
        }
        return -1;
    }
}

运行结果

姓名:张三-95分
姓名:赵六-92分
姓名:王五-67分
姓名:李四-89分
---------按顺序出队选座位------------
姓名:张三-95分
姓名:赵六-92分
姓名:李四-89分
姓名:李四-89分
姓名:王五-67分

逻辑上使用堆结构(完全二叉树)实现,物理上使用动态数组实现。 参考:https://blog.csdn.net/qq_35326718/article/details/72866180  https://blog.csdn.net/u013309870/article/details/71189189

(5) 比较器

        Queue<Integer> pq=new PriorityQueue<Integer>(new Comparator<Integer>(){
            public int compare(Integer a, Integer b){   // 这里要严格写成和上面的一样
                return b-a;
            }
        });

原来上面的compare方法中参数类型写成了 int, 以为也能编译通过,结果不行,要严格和Comparator中的泛型一致。自定义了比较器后就可以在Collections和Arrays的sort方法对容器中的元素进行排序,默认是升序排序的。

另两种比较器的使用形式:

public class LeetCode{
  public static void main(String[] args){
    List<MeetingTime> list=new ArrayList<>();
    MeetingTime m1=new MeetingTime(10,30);
    MeetingTime m2=new MeetingTime(5,10);
    list.add(m1);
    list.add(m2);
    Collections.sort(list);
  }
}

// 让一个类实现Compable接口,然后在集合中就可以直接比较这个元素了,也就是定义类的时候自带比较器
class MeetingTime implements Comparable<MeetingTime>{
  int startTime;
  int endTime;

  public void MettingTime(int startTime, int endTime){
    this.startTime=startTime;
    this.endTime=endTime;
  }

  @Override
  public int compareTo(MeetingTime m){
    return this.startTime-m.startTime;
  }
}
public class LeetCode{
  public static void main(String[] args){
    List<MeetingTime> list=new ArrayList<>();
    MeetingTime m1=new MeetingTime(10,30);
    MeetingTime m2=new MeetingTime(5,10);
    list.add(m1);
    list.add(m2);
    Collections.sort(list, new MyComparator());
  }

  // 单独定义一个实现Comparator接口的类,即单独弄一个通用的比较器,避免内部类不能复用的问题
  static class MyComparator implements Comparator<MeetingTime>{
    @Override
    public int compare(MeetingTime t1, MeetingTime t2){
      return t1.startTime-t2.startTime;
    }
  }
}

class MeetingTime {
  int startTime;
  int endTime;

  // 默认的构造函数是没有返回值的
  public MeetingTime(int startTime, int endTime) {
    this.startTime = startTime;
    this.endTime = endTime;
  }
}

上面用到了静态内部类的形式,这里复习下java静态类和非静态类的区别:https://www.cnblogs.com/muffe/p/6580208.html

(6) List在指定位置插入

void  add(int index, E element);

2. 关于字符和字符串,不同类型的数字

String判断相等要用equals方法,不能直接用等号。

利用trim()方法可以快速去除字符串的前导空白和尾部空白

(1) 相互转换

 int转String直接加""即可,String转int需要用到Integer.parseInt()方法。

 String转char数组直接调用toCharArray()方法,

 String与char互转,例如将“49”转化成‘49’

 char与int互转。

package CodeTest;

public class LeetCode {

  // int, char, String互转测试
  public static void main(String[] args) {
    int int49 = 49;
    int int4 = 4;

    /*-------int和char互转----------*/
    // char c = '49';  错误,应该是字符串
    char char49 = (char) int49;  //int -->char
    System.out.println((char) char49);   // 结果是1,因为49应该转为String,而不是char
    //System.out.println((String)char49); 错误,不可以这么用

    char char4;
    char4 = (char) int4;
    System.out.println(char4); //int -->char, 乱码,没有转成功

    char4 = (char) (int4 + 48);
    System.out.println(char4); //成功输出4,上面要加强转,否则编译不通过

    int4 = char4 - '0';
    System.out.println(int4); //char -->int, 直接减去字符0就可以了

    /*-------int和String互转----------*/
    System.out.println(String.valueOf(4));
    System.out.println(Integer.parseInt("4"));

    /*-------String和char互转----------*/
    char[] crs = "test".toCharArray();
    String str = String.valueOf(crs);

    char chr = '4';
    str = String.valueOf(chr);  // char -->String
    System.out.println(str);

    // str="4"; 对于单个字符的String --> char 好像还是只能用toCharArray
  }
}

(2) 快速逆转字符串

 String reversed = new StringBuilder(s).reverse().toString()

(3) split和replaceAll按多个字符串匹配

     // 这里用“|”来匹配多个替换,对于中括号,前面要加上转义字符 \
        String str=input.replaceAll(",| |\]|\[","");

(4) double, long, int

做算法题时遇到一个比较尴尬的问题,用到Math.pow()这个函数求指数的时候,因为它返回的是double,结果之前的变量用的是int或long,结果编译阶段各种出错,现在来总结下遇到的转换方式

int mod = (int)Math.pow(10, 9) + 7
// long res; int mod
return (int) (res % mod);    // 正确
return (int) res % mod;    // 错误,编译不通过

3. DFS&BFS&DP

BFS和DFS遍历时不要忘记加visited数组来标记已经访问过的数组,否则会重复遍历。

关于dp的一个心得:dp分为自顶向下和自低向上,其实两者都是从末端的临界开始往另一侧考虑,通俗的说就是从最边上的条件变化入手。

BFS如何出完一层之后,再出下一层?

4. 其它

一些有用的参考代码片断:

 nusm[0]=nums[n++]=1;  // 可以这么赋值但不可以这么定义
//return new int[2]{i+1,j+1}; 错误,编译不通过不能在此处加2
return new int[]{i+1,j+1};
for(int[] row:dp) Arrays.fill(row, Integer.MIN_VALUE);
        int[][] mp = new int[m][26];
        Map<String, Integer> dp = new HashMap<>();
        for (int i = 0; i < m; i++) 
            for (char c:stickers[i].toCharArray()) mp[i][c-'a']++
            for (int j = 0; j < 26; j++) {
                if (tar[j] > 0 ) 
                    for (int k = 0; k < Math.max(0, tar[j]-mp[i][j]); k++)
                        sb.append((char)('a'+j));
            }
原文地址:https://www.cnblogs.com/f91og/p/9629645.html