Java基础知识总结(刷力扣必备)

目录

零、前言

0.1Java的输入

0.2 Java的输出

一、数组Array和动态数组ArrayList

1.1有关数组的Array转换和排序

1.2 有关ArrayList的用法、自定义排序

1.3 ArrayList和数组int[]的相互转化

 1.4 二维的ArrayList

1.4 数组的经典例题

1.4.1 242. 有效的字母异位词

1.4.2 383. 赎金信

二、 链表ListNode

2.1链表的基本概念与思想

2.2 链表的经典题目

2.2.1 21. 合并两个有序链表

2.2.2 203. 移除链表元素

2.2.3 206. 反转链表

2.2.4  24. 两两交换链表中的节点

2.2.5  19. 删除链表的倒数第 N 个结点

2.2.6  142. 环形链表 II

三 、哈希表

3.1  HashMap

3.1.1创建hashmap,添加键值对,进行查找和遍历

3.1.2 四种遍历Map方式:

3.1.3 hashmap进行自定义排序

3.2  HashSet

3.2.1创建HashSet

3.3 HashSet和HashMap的区别

3.4 哈希表经典例题

3.4.1 349. 两个数组的交集

 3.4.2 202. 快乐数

3.4.3 454. 四数相加 II

3.4.3 347. 前 K 个高频元素

四、JAVA字符串和StringBuilder

4.1 JAVA字符串

4.2 StringBuilder

4.3 字符串和StringBuilder经典题目

4.3.1 541. 反转字符串 II

4.3.2 151. 翻转字符串里的单词

4.3.3 剑指 Offer 58 - II. 左旋转字符串

4.3.4 KMP 28. 实现 strStr()

4.3.5 KMP 459. 重复的子字符串

五、栈与队列

5.1 Stack栈的用法(用双端队列Deque来实现)

5.3.1 栈 20. 有效的括号

5.3.2 栈 1047. 删除字符串中的所有相邻重复项

5.3.3 栈 150. 逆波兰表达式求值 (计算机如何处理表达式?)

5.3.4 队列 239. 滑动窗口最大值


零、前言

双指针法、动态规划、二叉树、回溯算法、贪心等算法见Java算法总结持续更新(附常见算法题代码实现)_青衫倚斜桥的博客-CSDN博客_java常见算法编程题 

刷题顺序见:

GitHub - youngyangyang04/leetcode-master: 《代码随想录》LeetCode 刷题攻略:200道经典题目刷题顺序,共60w字的详细图解,视频难点剖析,50余张思维导图,支持C++,Java,Python,Go,JavaScript等多语言版本,从此算法学习不再迷茫!🔥🔥 来看看,你会发现相见恨晚!🚀

头文件:HJ10 字符个数统计

import java.util.*;
public class Main{
    public static int com(String s){
        Set<Character> set=new HashSet<Character>();
        for(int i=0;i<s.length();i++){
            set.add(s.charAt(i));
        }
        return set.size();
    }
    public static void main(String[] args){
        Scanner input=new Scanner(System.in);
        String s=input.nextLine();
        int res=com(s);
        System.out.println(res);
    }
}

0.1Java的输入

Java Scanner类的常用方法及用法(很详细)_码农翻身的博客-CSDN博客_java scanner用法

Scanner类的常用方法

此处重点讲一下next()和nextLine()的区别
next():只读取输入直到空格。它不能读两个由空格或符号隔开的单词。此外,next()在读取输入后将光标放在同一行中。(next()只读空格之前的数据,并且光标指向本行)

nextLine():读取输入,包括单词之间的空格和除回车以外的所有符号(即。它读到行尾)。读取输入后,nextLine()将光标定位在下一行。

 正常的输入输出:

				Scanner input = new Scanner(System.in);
				System.out.println("请输入一个字符串(中间能加空格或符号)");
				String a = input.nextLine();
				System.out.println("请输入一个字符串(中间不能加空格或符号)");
				String b = input.next();
				System.out.println("请输入一个整数");
				int c;
				c = input.nextInt();
				System.out.println("请输入一个double类型的小数");
				double d = input.nextDouble();
				System.out.println("请输入一个float类型的小数");
				float f = input.nextFloat();
  •  java输入一串数字,排序后再输出。
    
    import java.util.Arrays;
    import java.util.Scanner;
    
    public class Learn1 {undefined
     //输入一串数字,排序后再输出
      public static void main(String[] args) {
         Scanner in = new Scanner(System.in);
         String temp=in.nextLine();
         int len = temp.length();
         int[] arr = new int[len];
     
         for(int i=0;i<len;i++) {
             arr[i]=Integer.parseInt(temp.substring(0,1));
             temp=temp.substring(1);
         }
         Arrays.sort(arr);
         for(int j=0;j<len;j++) {
             System.out.print(arr[j]);
         }
     
      }
    
    }
    
    

 Scanner类的常用方法2

这里写图片描述

Scanner scan = new Scanner(System.in);	//构造Scanner类的对象scan,接收从控制台输入的信息
				System.out.println("请输入你的姓名");
				String name = scan.nextLine();//接收一个字符串,可以加除Enter以外的所有符号,包括空格和Tab
				System.out.println("请输入你的ID");
				String ID ;
				while(scan.hasNextLine()) {// hasNextLine()方法判断当前是否有输入,当键盘有输入后执行循环
					if(scan.hasNextInt()) {// 判断输入的值是否为整数类型,当为整数类型时执行循环
						ID = scan.nextLine();
						System.out.println("你输入的姓名为:"+name);
						System.out.println("你输入的ID为:"+ID);
						break;
					}else {
						System.out.println("请输入数字哦!");
						ID = scan.nextLine();
						continue;
					}
				}

0.2 Java的输出

java toString()方法的使用和详解 java toString()方法的使用和详解_码农回顾-CSDN博客_tostring方法怎么用

int[] arr ={1,2,3,4,5};
String arrString = Arrays.toString(arr);
//输出[I@7150bd4d
System.out.println(arrString);
//输出[1, 2, 3, 4, 5]

一、数组Array和动态数组ArrayList

1.1有关数组的Array转换和排序

最大值:Integer.MAX_VALUE

最小值:Integer.MIN_VALUE

  • 初始化定义数组
  • 查看数组的长度: length=arr2.length;
  • 遍历数组
  • 如何输出数组 : Arrays.toString(array3); 输出的是[1, 2, 3]
  • String 转换成 char数组: s.toCharArray();
  • char数组转换为String: String s1=new String(char1);
  • 判断两个数组是否相等:Arrays.equals(str1, str2);
  • 对数组进行排序:Arrays.sort(arr2);
int[] arr2=new int[]{1,2,3,4,5};
int[] noteCount = new int[26]; 
// //查看数组的长度
int length=arr2.length;
System.out.println("arr2:  "+Arrays.toString(arr2));
 //遍历数组
    for (int i = 0; i < arr2.length; i++) {
    	     System.out.println(arr2[i]);
    }
//输出数组 输出[1,2,3,4]
    int[]  array3={1,2,3,4};
    String s=Arrays.toString(array3);
    System.out.println("arrStrings:"+s);
// String 转换成char[]数组
char[] chararray = s.toCharArray();
//char[]数组转换为String
String s1= new String(chararray);
//判断两个数组是否相等
return Arrays.equals(str1, str2);
  • 二维数组的自定义排序 Arrays.sort
  • 从小到大排序
int [][] people={{7,0},{4,4},{7,1},{5,0},{6,1},{5,2}};
        int len=people.length;
        for (int[] person : people) {
        	String ans=Arrays.toString(person);
            System.out.println(ans);
        }
        Arrays.sort(people, new Comparator<int[]>() {
            public int compare(int[] person1, int[] person2) {
                if (person1[0] != person2[0]) {
                    return person2[0] - person1[0];
                } 
                else {
                    return person2[1] - person1[1];
                }
            }
        });
        System.out.println();
        for (int[] person : people) {
        	String ans=Arrays.toString(person);
            System.out.println(ans);
        }

1.2 有关ArrayList的用法、自定义排序

ArrayList见Java ArrayList | 菜鸟教程

LinkedList用法类似 Java LinkedList | 菜鸟教程

  • 通过索引来获取元素 sites.get(i)

  • 添加 sites.add(int index,E element)如sites.add(1, "Weibo");

  • 修改元素 sites.set(2, "Wiki"); // 第一个参数为索引位置,第二个为要修改的值

  •  删除最后一个元素 String a=sites.remove(sites.size()-1);

  • 计算大小 sites.size()

  • 判断元素是否在 arraylist  sites.contains();

  • 截取部分 arraylist 的元素 subList() subList(1,3);

  • 判断 arraylist 是否为空  isEmpty()

  • 将 arraylist 转换为数组 toArray()

  • 将 arraylist 转换为字符串 toString()

  • 如果是char型的新建必须是:ArrayList<Character> sites=new ArrayList<Character>();

ArrayList<String> sites = new ArrayList<String>();
        sites.add("Google");
        sites.add("Runoob");
        sites.add("Taobao");
        sites.add("Weibo");
        System.out.println("数组遍历-方法1");
        for (int i = 0; i < sites.size(); i++) {
            System.out.println(sites.get(i));
        }
        System.out.println("数组遍历-方法2");
        for(String i : sites)
        {
        	System.out.println(i);
        }
      //是否包含
      // 检查 Runoob 是否在这个数组中
        System.out.println(sites.contains("Runoob"));
      //删除最后一个元素
        String a=sites.remove(sites.size()-1);
        System.out.println(a);
  • ArrayList排序和反转
 ArrayList<String> sites = new ArrayList<>();
        sites.add("Runoob");
        sites.add("Google");
        sites.add("Wiki");
        sites.add("Taobao");
        System.out.println("不排序: " + sites);
        // 元素进行升序排列
        Collections.sort(sites);  // 字母排序
        System.out.println("排序后: " + sites);
       // 降序
        sites.sort(Comparator.reverseOrder());
        System.out.println("降序排序: " + sites);
     // 数组反转
        Collections.reverse(sites);
        System.out.println("数组反转 " + sites);
  • ArrayList自定义排序
//自定义一个比较器数组排序
	public static class reverse2 implements Comparator<Integer>
	{
		public int compare(Integer o1, Integer o2) {
            return -(o1-o2);
        }
	}
	public static void arraylist_sort(){
        //自定义排序
        ArrayList<Integer> list_1 = new ArrayList<>();
        list_1.add(1);list_1.add(7); list_1.add(3); list_1.add(6); list_1.add(5);
        list_1.add(5);
        System.out.println("排序前:");
        for (int i : list_1) {
            System.out.print(i);
        }
        //自定义一个比较器从大到小排序
        ArrayList_.reverse2 r2= new reverse2();
        Collections.sort(list_1,r2);
//        Collections.sort(list_1, new Comparator<Integer>() {
//            @Override
//            public int compare(Integer o1, Integer o2) {
//                return -(o1-o2);
//            }
//        });
        System.out.println("新建一个Comparator r2进行排序");
        System.out.println("排序后:");
        for (int i : list_1) {
            System.out.print(i);
        }
        System.out.println();
  • 自定义用hashmap 排序
  • 按照arr2的排序方式对arr1进行排序,若arr1的值不在arr2之中,则就按照从小到大的顺序排序。
//自定义用hashmap 排序
        //按照arr2的排序方式对arr1进行排序,若arr1的值不在arr2之中,则就按照从小到大的顺序排序。
        Integer [] arr1= {2,3,1,3,2,4,6,7,9,2,19};
        Integer [] arr2= {2,1,4,3,9,6};
        HashMap<Integer, Integer> map = new HashMap<>();
        ArrayList<Integer> list = new ArrayList<>();
        for(int num : arr1) list.add(num);
        for(int i = 0; i < arr2.length; i++) map.put(arr2[i], i);
        Collections.sort(list, new Comparator<Integer>() {
        	@Override
            public int compare(Integer x, Integer y) {
        		if(map.containsKey(x) || map.containsKey(y)) return map.getOrDefault(x, 1001) - map.getOrDefault(y, 1001);
        		return x - y;
        	}
        });
        int j=0;
        for(Integer number : list) 
        	arr1[j++] = number;

1.3 ArrayList和数组int[]的相互转化

ArrayList转换到数组

List<Integer> integer_list = new ArrayList<Integer>();
integer_list.add(1);
integer_list.add(2);

 Integer动态数组转Integer数组
Integer[] ids_integer = new Integer[integer_list.size()]);
integer_list.toArray(ids_integer);
System.out.println(Arrays.toString(ids_integer));

// Integer动态数组转int数组
int[] ids_int = new int[integer_list.size()];
for (int i = 0; i < integer_list.size(); i++) {
	ids_int[i] = integer_list.get(i);
}

// Integer动态数组转int数组
int[] arr = new int[integer_list.size()];
for(Integer number : list) 
        arr1[j++] = number;

System.out.println(Arrays.toString(ids_int));

数组转换到ArrayList

        //数组转到动态数组
		int[] a={1,2,3,4,5};
		int len=a.length;
		ArrayList<Integer> list=new ArrayList<>();
        for(int i:a){
            list.add(i);
        }
        System.out.print(list);

 1.4 二维的ArrayList

package ArrayLIst_2;
import java.util.*;
public class ArrayList_2 {
	//定义二维数组
	public static void Array_2() {
		List<List<Integer>> ret = new ArrayList<ArrayList<Integer>>();
		for(int i=1;i<10;i++) {
			ArrayList<Integer> level = new ArrayList<Integer>();
			for(int j=0;j<i;j++) {
				level.add(j);
			}
			ret.add(level);
		}
		int currentLevelSize = ret.size();
		System.out.println(currentLevelSize);
		System.out.println(ret);
		ret.get(0).add(1000);
		System.out.println(ret);
		
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Array_2();
	}

}

 1.5 多维的ArrayList

可以通过class 的思想来创建多维的Arraylist

    public static class Stu {
        int val;
        String name;
        public Stu(int x, String y) {
            val = x;
            name=y;
        }
    }
    public static void main(String[] args) {
        Stu stu1 = new Stu(1,"aa");
        Stu stu2 = new Stu(2,"bb");
        Stu stu3 = new Stu(3,"cc");
        List <Stu> cla = new ArrayList<Stu>();
        cla.add(stu1);
        cla.add(stu2);
        cla.add(stu3);
        for(Stu s: cla){
            System.out.print(s.val+s.name);
        }
        //1aa2bb3cc
    }

数组的经典例题

1.4.1 242. 有效的字母异位词

class Solution {
    public boolean isAnagram(String s, String t) {
        if(s.length()!=t.length()){
            return false;
        }
        char[] c1=s.toCharArray();
        char[] c2=t.toCharArray();
        Arrays.sort(c1);
        Arrays.sort(c2);
        return Arrays.equals(c1, c2);
    }
}

1.4.2 383. 赎金信

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        int[] r1= new int[26];
        int[] m1= new int[26];
        for(int i=0;i<magazine.length();i++){
            m1[magazine.charAt(i)-'a']++;
        }
        for(int j=0;j<ransomNote.length();j++){
            r1[ransomNote.charAt(j)-'a']++;
        }
        for(int i=0;i<r1.length;i++){
            if (m1[i]<r1[i]) return false;
        }
        return true;
    }
}

989. 数组形式的整数加法


二、 链表ListNode

2.1链表的基本概念与思想

GitHub - youngyangyang04/leetcode-master: 《代码随想录》LeetCode 刷题攻略:200道经典题目刷题顺序,共60w字的详细图解,视频难点剖析,50余张思维导图,支持C++,Java,Python,Go,JavaScript等多语言版本,从此算法学习不再迷茫!🔥🔥 来看看,你会发现相见恨晚!🚀

解析:解决链表的题目一般要自定义个一个虚拟头节点和cur指针,       

ListNode dummyHead = new ListNode(0);//创建一个 dummyHead 虚拟头结点

ListNode curr = dummyHead;

之后对curr进行操作,最后返回dummyHead.

707. 设计链表

  • get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
  • addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
  • addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
  • addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val  的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
  • deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
public class ListNode{
    int val;
    ListNode next;
    ListNode() {};
    ListNode(int x)
        {val = x;}
}
class MyLinkedList {
    int size;
    ListNode head;
    /** Initialize your data structure here. */
    public MyLinkedList() {
        size=0;
        head= new ListNode(0);
    }
    
    /** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
    public int get(int index) {
        if(index>=size || index<0) return -1;
        ListNode cur= head;
        for(int i=0;i<index;i++){
            cur=cur.next;
        }
        return cur.next.val;
    }
    
    /** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
    public void addAtHead(int val) {
        addAtIndex(0,val);
    }
    
    /** Append a node of value val to the last element of the linked list. */
    public void addAtTail(int val) {
        addAtIndex(size,val);
    }
    
    /** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
    public void addAtIndex(int index, int val) {
        if (index > size) return ;
        if (index<0) index=0;
        ++size;
        ListNode cur= head;
        for(int i=0;i<index;i++){
            cur=cur.next;
        }
        ListNode toAdd = new ListNode(val);
        toAdd.next=cur.next;
        cur.next=toAdd;
    }
    
    /** Delete the index-th node in the linked list, if the index is valid. */
    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) return;
        size--;
        ListNode cur= head;
        for(int i=0;i<index;i++){
            cur=cur.next;
        }
        cur.next=cur.next.next;
    }
}

2.2 链表的经典题目

2.2.1 21. 合并两个有序链表

给定两个链表,将链表合并从小到大排序输出(需要自定义个一个链表和一个表头)力扣

class Solution {
  public ListNode mergeTwoLists(ListNode l1, ListNode l2) 
  {
        ListNode dummyHead = new ListNode(0);//创建一个新链表, dummyHead 虚拟头结点
		ListNode curr = dummyHead;
		while(l1 != null && l2 != null)
		{	if(l1.val < l2.val)
			{
				curr.next = l1;
				curr = curr.next;
				l1 = l1.next;
			}
			else
			{
				curr.next = l2;
				curr = curr.next;
				l2 = l2.next;
			}
		}
		// 有一方为空时,直接将剩下的链接到 curr 上
		if(l1 == null)
			curr.next = l2;
		else
			curr.next = l1;
		return dummyHead.next; // 从头结点之后开始返回,也就是合并之后的链表
  }
}

2.2.2 203. 移除链表元素

要建一个虚拟头节点 dummynode。

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。力扣

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        //创建一个虚拟节点
        ListNode dummynode=new ListNode();
        //dummynode.next=head;
        //定义对链表操作的指针
        ListNode curr=dummynode;
        curr.next=head;
        while(curr.next!=null){
            if(curr.next.val==val){
                curr.next=curr.next.next;
            }
            else{
                curr=curr.next;
            }
        }
        return dummynode.next;
    }
}

2.2.3 206. 反转链表

这道题不用新建虚拟头节点,因为最后pre刚好到头,需要建立双指针

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

假设链表为 1→2→3→∅,我们想要把它改成 ∅←1←2←3。

定义两个指针: prepre 和 curcur ;prepre 在前 curcur 在后。
每次让 prepre 的 nextnext 指向 curcur ,实现一次局部反转
局部反转完成之后,prepre 和 curcur 同时往前移动一个位置
循环上述过程,直至 prepre 到达链表尾部

力扣

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre=head;
        ListNode curr=null;
        while(pre!=null){
            ListNode tempnext=pre.next;
            pre.next=curr;
            curr=pre;
            pre=tempnext;
        }
        return curr;
    }
}

2.2.4  24. 两两交换链表中的节点

 步骤一->步骤三->步骤二

力扣

24.两两交换链表中的节点1

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummynode=new ListNode(0);
        dummynode.next=head;
        ListNode curr=dummynode;
        while(curr.next!=null&&curr.next.next!=null){
            ListNode temp1=curr.next;
            ListNode temp2=curr.next.next;
            curr.next=temp2;
            temp1.next=temp2.next;
            temp2.next=temp1;
            curr=temp1;
        }
        return dummynode.next;
    }
}

2.2.5  19. 删除链表的倒数第 N 个结点

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 

解析: 巧用双指针

双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。

2.2.6  142. 环形链表 II

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

解题思路:1 快慢指针

slow * 2 = fast;
slow = a + b;
fast = a + b + c + b = a + 2*b + c;
(a + b)*2 = a + 2*b + c;
a = c;
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode pos=head;
        ListNode fast=head;
        ListNode slow=head;
        if(head==null) return null;
        while(fast!=null){
            if(fast.next!=null){
                fast=fast.next.next;
            }
            else{
                return null;
            }
            slow=slow.next;    
            if(fast==slow){
                while(slow!=pos){
                    slow=slow.next;
                    pos=pos.next;
                }
                return pos;
            }
        }
        return null;  
    }
}

2 哈希表 

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode pos=head;
        HashSet<ListNode> visited= new HashSet<ListNode>();
        while(pos!=null){
            if(visited.contains(pos)){
                return pos;
            }
            else {
                visited.add(pos);
            }
            pos=pos.next;
        }
        return null;      
    }
}

三 、哈希表

力扣

3.1  HashMap

HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key

HashMap实现了Map接口,Map接口对键值对进行映射。Map中不允许重复的键。Map接口有两个基本的实现,HashMap和TreeMap。TreeMap保存了对象的排列次序,而HashMap则不能。HashMap允许键和值为null。HashMap是非synchronized的,但collection框架提供方法能保证HashMap synchronized,这样多个线程同时访问HashMap时,能保证只有一个线程更改Map。

主要对外接口:

  • clear()
    clear() 的作用是清空HashMap。它是通过将所有的元素设为null来实现的。
  • containsKey(key)
    containsKey() 的作用是判断HashMap是否包含key。
  • containsValue(value)
    containsValue() 的作用是判断HashMap是否包含“值为value”的元素。
  • entrySet()、values()、keySet()
    entrySet()的作用是返回“HashMap中所有Entry的集合”,它是一个集合。
  • for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
        }
     
  • get(key)
    get() 的作用是获取key对应的value
  • getOrDefault(key, defaultValue) 获取key对应的value,如果没有则是defaultValue

  • put(key,value)
    put() 的作用是对外提供接口,让HashMap对象可以通过put()将“key-value”添加到HashMap中。
  • putAll(map)
    putAll() 的作用是将"m"的全部元素都添加到HashMap中
  • remove(key)
    remove() 的作用是删除“键为key”元素
  • clone()
    克隆一个HashMap,并返回Object对象

3.1.1创建hashmap,添加键值对,进行查找和遍历

	public static void create_HashMap(){
        // 创建一个Hash_map
		HashMap<Integer, Integer> Sites = new HashMap<Integer, Integer>();
        // 添加键值对
        Sites.put(2, 100);
        Sites.put(4, 200);
        Sites.put(6, 300);
        Sites.put(8, 400);
        System.out.println(Sites);
		//结果为 true
		System.out.println(hashMap.containsKey(8));

        int[] array_hashkey=new int[Sites.size()];
         //进行迭代
        // 对hashmap的每个key进行迭代
        for (Integer i : Sites.keySet())
        {
        	System.out.println("key: " + i + " value: " + Sites.get(i));
        }
       // 对hashmap的每个value进行迭代
        for (Integer value : Sites.values())
        {
        	System.out.print(value + ", ");
        }
    }

3.1.2 四种遍历Map方式:

public static void main(String[] args) {
 
    Map<String, String> map = new HashMap<String, String>();
    map.put("1", "value1");
    map.put("2", "value2");
    map.put("3", "value3");
  
    //第一种:普遍使用,二次取值
    System.out.println("通过Map.keySet遍历key和value:");
    for (String key : map.keySet()) {
        System.out.println("key= "+ key + " and value= " + map.get(key));
    }
  
    //第二种
    System.out.println("通过Map.entrySet使用iterator遍历key和value:");
    Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry<String, String> entry = it.next();
        System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
    }
  
    //第三种:推荐,尤其是容量大时
    System.out.println("通过Map.entrySet遍历key和value");
    for (Map.Entry<String, String> entry : map.entrySet()) {
        System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
    }
 
    //第四种
    System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
    for (String v : map.values()) {
        System.out.println("value= " + v);
    }
 }

3.1.3 hashmap进行自定义排序 根据value的值来进行排序并输出

import java.util.*;
class Test
{
	private static class ValueComparator implements Comparator<Map.Entry<String,Integer>>
	{
		public int compare(Map.Entry<String,Integer> m,Map.Entry<String,Integer> n)
		{
            //后一个减前一个是从大到小排序
			return n.getValue()-m.getValue();
		}
	}
	public static void main(String[] args) 
	{
		Map<String,Integer> map=new HashMap<>();
		map.put("a",1);
		map.put("c",3);
		map.put("b",5);
		map.put("f",7);
		map.put("e",6);
		map.put("d",8);
		List<Map.Entry<String,Integer>> list=new ArrayList<>();
		list.addAll(map.entrySet());
		Test.ValueComparator vc=new ValueComparator();
		Collections.sort(list,vc);
		for(Iterator<Map.Entry<String,Integer>> it=list.iterator();it.hasNext();)
		{
			System.out.println(it.next());
		}
	}
}

第二种排序方法:

String str="My name is Benjamin. I am 12. 3th. But my friends like to call me “Big Ben”, because my size is quite big.";
        str=str.toLowerCase();
        String [] words=str.split("\\W+");//正则表达式
        Map<String,Integer> hashmap = new HashMap<String,Integer>();
        Set<String> wordset= new HashSet<String>();
        int len=words.length;
        for(int i=0; i<len; i++) {
            if(wordset.contains(words[i])) {
                Integer num=hashmap.get(words[i]);
                num++;
                hashmap.put(words[i],num);
            }
            else {
                hashmap.put(words[i],1);
                wordset.add(words[i]);
            }
        }
        List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String,Integer>>(hashmap.entrySet());
        Collections.sort(list, new Comparator<Map.Entry<String,Integer>>(){
            public int compare(Map.Entry<String,Integer> o1, Map.Entry<String,Integer> o2){
                return (o2.getValue()-o1.getValue());
            }
        });
        String [] res = new String [list.size()];
        int i=0;
        for (Map.Entry<String,Integer> t:list){
            String s = new String();
            s=t.getKey()+","+t.getValue();
                res[i]=s;
                i++;
        }
        String ar=Arrays.toString(res);
        System.out.println(ar);

3.2  HashSet

HashSet实现了Set接口,它不允许集合中有重复的值,当我们提到HashSet时,第一件事情就是在将对象存储在HashSet之前,要先确保对象重写equals()和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有储存相等的对象。如果我们没有重写这两个方法,将会使用这个方法的默认实现。

public boolean add(Object o)方法用来在Set中添加元素,当元素值重复时则会立即返回false,如果成功添加的话会返回true。

3.2.1创建HashSet

  • HashSet一定不含有重复的值,并且输出的顺序是随机的。
  • 遍历HashSet时没有get方法,用for (Integer integer : set) 
public static void main(String[] args) {
		HashSet<Integer> set =new HashSet<>();
		set.add(22);set.add(3);set.add(8);set.add(8);set.add(3);
		
		//遍历这个hashset 输出3 12 8
		//1.foreach
		for (Integer integer : set) {
			System.out.println(integer);
		}
		//2.迭代器
		Iterator<Integer> iterator=set.iterator();
		while(iterator.hasNext()){
			Integer integer=iterator.next();
			System.out.println(integer);
		}
		//对比查找
		System.out.println(set.contains(22));
		//清空
		set.clear();
		//获取长度
		System.out.println(set.size());
	}

3.3 HashSet和HashMap的区别

HashMap和HashSet都是collection框架的一部分,它们让我们能够使用对象的集合。

collection框架有自己的接口和实现,主要分为Set接口,List接口和Queue接口。它们有各自的特点:

Set 的集合里不允许对象有重复的值 。
List 允许有重复,它对集合中的对象进行索引。
Queue 的工作原理是FCFS算法(First Come, First Serve)。

*HashMap**HashSet*
HashMap实现了Map接口HashSet实现了Set接口
HashMap储存键值对HashSet仅仅存储对象
使用put()方法将元素放入map中使用add()方法将元素放入set中
HashMap中使用键对象来计算hashcode值HashSet使用成员对象来计算hashcode值,对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象的相等性,如果两个对象不同的话,那么返回false
HashMap比较快,因为是使用唯一的键来获取对象HashSet较HashMap来说比较慢

3.4 哈希表经典例题

3.4.1 349. 两个数组的交集

给定两个数组nums1和nums2,编写一个函数来计算它们的交集。用HashSet

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        Set<Integer> visited = new HashSet<Integer>();
        Set<Integer> res = new HashSet<Integer>();
        for(Integer i : nums1){
            visited.add(i);
        }
        for(Integer j : nums2){
            if(visited.contains(j)){
                res.add(j);
            }
        }
        int[] res_int=new int[res.size()];
        int i=0;
        for(Integer s:res){
            res_int[i]=s;
            i++;
        }
        return res_int;
    }
}

 3.4.2 202. 快乐数

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」定义为:

对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果 可以变为  1,那么这个数就是快乐数。
如果 n 是快乐数就返回 true ;不是,则返回 false 。

输入:19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

class Solution {
    public int next(int n){
        int res=0;
        while(n>0){
            res=res+(n%10)*(n%10);
            n=n/10;
        }
        return res;
    }
    public boolean isHappy(int n) {
        Set<Integer> visited=new HashSet<Integer>();
        while(n!=1){
            if(visited.contains(n)){
                return false;
            }
            visited.add(n);
            n=next(n);
        }
        return true;
    }
}

3.4.3 454. 四数相加 II

给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。

我们可以将四个数组分成两部分,AA 和 BB 为一组,CC 和 DD 为另外一组。

对于 AA 和 BB,我们使用二重循环对它们进行遍历,得到所有 A[i]+B[j]A[i]+B[j] 的值并存入哈希映射中。对于哈希映射中的每个键值对,每个键表示一种 A[i]+B[j]A[i]+B[j],对应的值为 A[i]+B[j]A[i]+B[j] 出现的次数。

对于 CC 和 DD,我们同样使用二重循环对它们进行遍历。当遍历到 C[k]+D[l]C[k]+D[l] 时,如果 -(C[k]+D[l])−(C[k]+D[l]) 出现在哈希映射中,那么将 -(C[k]+D[l])−(C[k]+D[l]) 对应的值累加进答案中。

最终即可得到满足 A[i]+B[j]+C[k]+D[l]=0A[i]+B[j]+C[k]+D[l]=0 的四元组数目。

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        int res=0;
        HashMap<Integer,Integer> sumAB=new HashMap<Integer,Integer>();
        //key是数组A和数组B元素两两相加之合,value是出现的个数
        for(Integer i : nums1){
            for(Integer j:nums2){
                sumAB.put(i+j,sumAB.getOrDefault(i+j,0)+1);
            }
        }
        for(Integer c:nums3){
            for(Integer d:nums4){
                if(sumAB.containsKey(-c-d)){
                    res=res+sumAB.get(-c-d);
                }
            }
        }
        return res;
    }
}

3.4.3 347. 前 K 个高频元素

class Solution {
    	public static class ValueComparator implements Comparator<Map.Entry<Integer,Integer>>
	{
		public int compare(Map.Entry<Integer,Integer> m,Map.Entry<Integer,Integer> n)
		{
			return n.getValue()-m.getValue();
		}
	}

    public int[] topKFrequent(int[] nums, int k) {
        HashMap<Integer,Integer> map=new HashMap<Integer,Integer>();
        int len =nums.length;
        for(int i=0;i<len;i++){
            if(map.containsKey(nums[i])){
                map.put(nums[i],map.get(nums[i])+1);
            }
            else{
                map.put(nums[i],1);
            }
        }
        List<Map.Entry<Integer,Integer>> list=new ArrayList<>();
		list.addAll(map.entrySet());
		Solution.ValueComparator vc=new ValueComparator();
		Collections.sort(list,vc);
        Iterator<Map.Entry<Integer, Integer>> iter = list.iterator();
        int[] res=new int[k];
		for(int i=0;i<k;i++){
			Map.Entry<Integer, Integer> item = iter.next();
			int key = item.getKey();
            res[i]=key;
		}
        return res;
    }
}

四、JAVA字符串和StringBuilder

4.1 JAVA字符串

Java String 类 | 菜鸟教程

  • 字符串的大小  len=str.length();
  • 提取字符串中的某一个下标 str.charAt(6)
  • 查找字符出现的位置str.indexOf('o')
  • 找子串 str.substring(4,5)
  • 反转 String string="runoob"; String reverse = new StringBuffer(string).reverse().toString();
  • 字符串判单是否相等 str.equals("+"); 为什么不能用==来判断?
  • 替换字符 public String replace(char searchChar, char newChar)

 在编程中,通常比较两个字符串是否相同的表达式是“==” ,但在 Java 中不能这么写。在 Java 中,如果要比较 a 字符串是否等于 b 字符串,需要这么写: if(a.equals(b)){ } 返回 true 或 false  String 的 equals()方法用于比较两个字符串是否相等。由于字符串是对象类型,所以不能 简单的用“==” (双等号)判断两个字符串是否相等,而使用 equals()方法比较两个对象的内 容。  例如字符串“abc” 和一个新的字符串“abc” 比较的结果为“true” 因为它们内容相同。 , 注意: equals()方法比较的是对象的内容(区分字母的大小写格式) ,但是如果使用“==”双等 号操作符比较两个对象时, 比较的是两个对象的内存地址, 所以它们不相等 (即使内容相同, 不同对象的内存地址也是不相同的);

//charAt(i)提取字符串中的某一个下标
		 String str = "www.runoob.com";
		 int len=str.length();
	     char result = str.charAt(6);
	     String s2="";
	     s2=s2+result;
	     System.out.println(s2);
//查找字符出现的位置indeOf
	        System.out.print("查找字符 o 第一次出现的位置 :" );
	        System.out.println(str.indexOf( 'o' ));
//找子串substring
	        System.out.print("substring(4,5)返回值 :" );
	        System.out.println(Str.substring(4,5) );
  • 字符串转数字 Integer.parseInt(Str); 
  • 数字转字符串 String s = inta+""; 或者 String s1=x.toString();
  • 字符串转数组 char[] c=s.toCharArray();
  • 数组转字符串 String res=new String(c);
//字符串转数字int 数字转字符串
			String Str = new String("123");
			Integer a=Integer.parseInt(Str);
			int a2 = Integer.parseInt(Str);
			double b=Double.parseDouble(Str);
			int inta=234;
			String s = inta+"";
			char c='1';
			Integer x = 5;
	        System.out.println(x);  
			String s1=x.toString();

 4.1.1 字符串str.split函数

str.split函数的目的是分割字符串,然后保存到一个String数组中

String str="My name is Benjamin.";
str=str.toLowerCase();
String [] words=str.split("\\W+");//正则表达式 按照空格进行分割
        String ar1=Arrays.toString(words);
        System.out.println(ar1);
//[my, name, is, benjamin]

4.2 StringBuilder

Java StringBuffer 和 StringBuilder 类 | 菜鸟教程

  •  charAt() 方法用于返回指定索引处的字符。索引范围为从 0 到 length() - 1。
  • 增加 sb.append
  • 插入  sb.insert(8, "Java");
  • 删除  sb.delete(5,8);
  • 删除指定元素 sb.deleteCharAt(top);
  • 提取字串 sb.substring(0,3);
  • 删除最后的元素 sb.delete(len-1,len);
  • 反转 sb.reverse();
  • 返回长度(字符数)sb.length()
  • 返回字符串 toString()
			String s="www.runoob.com";
			StringBuilder sb = new StringBuilder(s);
		  
	        sb.append("Runoob..");
	        System.out.println(sb);  
	        sb.append("!");
	        System.out.println(sb);
	        //插入
	        sb.insert(8, "Java");
	        System.out.println(sb); 
	        //删除
	        sb.delete(5,8);
	        System.out.println(sb); 
	        //提取字串
	        String substring=sb.substring(0,3);
	        System.out.print("提取字串");
	        System.out.println(substring); 
			//删除最后的元素
	        int len=sb.length();
	        sb.delete(len-1,len);
	        System.out.print("删除最后的元素");
	        System.out.println(sb); 

4.3 字符串和StringBuilder经典题目

4.3.1 541. 反转字符串 II

给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。

如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

输入: s = "abcdefg", k = 2
输出: "bacdfeg"
class Solution {
    public String reverseStr(String s, int k) {
        char[] c=s.toCharArray();
        for(int start=0;start<c.length;start=start+2*k){
            //进行字符反转
            int i=start;
            int j=Math.min(start+k-1,c.length-1);
            while(i<j){
                char temp=c[i];
                c[i]=c[j];
                c[j]=temp;
                i++;
                j--;
            }
        }
        String res=new String(c);
        return res;

    }
}

4.3.2 151. 翻转字符串里的单词

给定一个字符串,逐个翻转字符串中的每个单词。

输入: "a good   example"
输出: "example good a"
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。先整体反转再局部反转。

class Solution {
    public String reverseWords(String s) {
        //去除两边的空格
        StringBuilder sb = trimSpaces(s);
        // 翻转字符串
        sb.reverse();
        // 翻转每个单词
        reverseEachWord(sb);
        return sb.toString();
    }

    public StringBuilder trimSpaces(String s) {
        int left = 0, right = s.length() - 1;
        // 去掉字符串开头的空白字符
        while (left <= right && s.charAt(left) == ' ') {
            ++left;
        }

        // 去掉字符串末尾的空白字符
        while (left <= right && s.charAt(right) == ' ') {
            --right;
        }

        // 将字符串间多余的空白字符去除
        StringBuilder sb = new StringBuilder();
        while (left <= right) {
            char c = s.charAt(left);

            if (c != ' ') {
                sb.append(c);
            } else if (sb.charAt(sb.length() - 1) != ' ') {
                sb.append(c);
            }
            ++left;
        }
        return sb;
    }
    public void reverse(StringBuilder sb, int left, int right) {
        while (left < right) {
            char tmp = sb.charAt(left);
            sb.setCharAt(left++, sb.charAt(right));
            sb.setCharAt(right--, tmp);
        }
    }
    public void reverseEachWord(StringBuilder sb) {
        int n = sb.length();
        int start = 0, end = 0;

        while (start < n) {
            // 循环至单词的末尾
            while (end < n && sb.charAt(end) != ' ') {
                ++end;
            }
            // 翻转单词
            reverse(sb, start, end - 1);
            // 更新start,去找下一个单词
            start = end + 1;
            ++end;
        }
    }
}

4.3.3 剑指 Offer 58 - II. 左旋转字符串

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。

输入: s = "lrloseumgh", k = 6
输出: "umghlrlose"
class Solution {
    public String reverseLeftWords(String s, int n) {
        char[] c1=s.toCharArray();
        int i=0;
        int len=c1.length;
       while(i<n){
           char temp=c1[0];
           for(int j=0;j<len-1;j++){
               c1[j]=c1[j+1];
           }
           c1[len-1]=temp;
           i++;
       }
       String res=new String(c1);
       return res;
    }
}

4.3.4 KMP 28. 实现 strStr()

 return haystack.indexOf(needle); 

4.3.5 KMP 459. 重复的子字符串

五、栈与队列

5.1 Stack栈的用法(用双端队列Deque来实现)

【Java】Java双端队列Deque使用详解_devnn的专栏-CSDN博客_deque java

Java双向队列Deque栈与队列_一念永恒-CSDN博客_dequeue java

Deque有三种用途:一次只能用一种!
普通队列(一端进另一端出):
Queue queue = new LinkedList()
双端队列(两端都可进出)
Deque deque = new LinkedList()
堆栈
Deque deque = new LinkedList()

注意:Java堆栈Stack类已经过时,Java官方推荐使用Deque替代Stack使用。Deque堆栈操作方法:push()、pop()、peek()。

  • 要讲栈和队列,首先要讲Deque接口。Deque的含义是“double ended queue”,即双端队列,它既可以当作栈使用,也可以当作队列使用。下表列出了Deque与Queue相对应的接口:

  • 下表列出了Deque与Stack对应的接口:

  • 判断为空
方法名描述
isEmpty()于检查此双端队列是“空”还是“非空”,不会引发异常

 汇总

第一个元素 (头部)最后一个元素 (尾部)
抛出异常特殊值抛出异常特殊值
插入addFirst(e)offerFirst(e)addLast(e)offerLast(e)
删除removeFirst()pollFirst()removeLast()pollLast()
查看getFirst()peekFirst()getLast()peekLast()

5.3.1 栈 20. 有效的括号

给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。

输入:s = "{[]}"
输出:true
class Solution {
    public boolean isValid(String s) {
        int len=s.length();
        HashMap<Character,Character> map=new HashMap<Character,Character>();
        map.put(')','(');
        map.put('}','{');
        map.put(']','[');
        if(len%2==1){
            return false;
        }
        Deque<Character> stack=new LinkedList<Character>();
        for(int i=0;i<len;i++){
            char x=s.charAt(i);
            if(map.containsKey(x)){
                if(stack.size()==0){
                    return false;
                }
                char y=stack.pop();
                if (y!=map.get(x)) return false;
            }
            else{
                stack.push(x);
            }
        }
        return stack.isEmpty();
}
}

5.3.2 栈 1047. 删除字符串中的所有相邻重复项

给出由小写字母组成的字符串 S重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。

class Solution {
    public String removeDuplicates(String s) {
        StringBuffer stack = new StringBuffer();
        int top = -1;
        for (int i = 0; i < s.length(); ++i) {
            char ch = s.charAt(i);
            if (top >= 0 && stack.charAt(top) == ch) {
                stack.delete(top,top+1);
                --top;
            } else {
                stack.append(ch);
                ++top;
            }
        }
        return stack.toString();
    }
}

5.3.3 栈 150. 逆波兰表达式求值 (计算机如何处理表达式?)

class Solution {
    public int evalRPN(String[] tokens) {
        Deque<Integer> num=new LinkedList<Integer>();
        int len=tokens.length;
        int res;
        for(int i=0;i<len;i++){
            String token=tokens[i];
            if(isNumber(token)){
                int token_num=Integer.parseInt(token);
                num.push(token_num);
            }
            else{
                int num1=num.pop();
                int num2=num.pop();
                switch(token){
                    case "+":
                        num.push(num1+num2);
                        break;
                    case "-":
                        num.push(num2-num1);
                        break;
                    case "*":
                        num.push(num2*num1);
                        break;
                    case"/":
                        num.push(num2/num1);
                        break;
                    default:
                }
            }
        }
        return num.pop();
}
    public boolean isNumber(String token){
        if(token.equals("+")||token.equals("-")||token.equals("*")||token.equals("/")){
            return false;
        }
        else {
            return true;
        }
    }
}

5.3.4 队列 239. 滑动窗口最大值

71. 简化路径

  • 8
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值