leetcode代码练习——Java的数据结构(具体使用)

14 篇文章 0 订阅

注:Java中所有的泛型必须是引用类型<Integer>而不是<int>
java提供的数学方法:
求最大值Math.max(10,15),最小值Math.min(10,15)
看取值范围:

int范围:-2^31-2^31-1   
double范围:-2^63-2^63-1
long范围:-2^63-2^63-1

-231 <= Node.val <= 231 - 1 要想有个比取值范围内都大的数double maxx=Double.MAX_VALUE
Integer.MAX_VALUE,Double.MAX_VALUE,Float.MAX_VALUE,Long.MAX_VALUE,Byte.MAX_VALUE

打印:for (Integer number : innerList) {
System.out.print(number + " ");
}
&& 符号有所谓的“短路原则”,当 A && B 出现时,如果A经判断是假,那么B表达式将不会获得执行或被判断的机会。直接结果就为假。
|| 前真后面就不去判断了,|前真后也会去判断

数组定义需要开空间,可以这样根据题目给出的大小开空间:

int s1=text1.length(),s2=text2.length();
int[][] dp=new int[s1+1][s2+1];//用定义的变量开空间

单个字符
Map<Character, Character> pairs = new HashMap<Character, Character>()

输入流

hasNext() 和 hasNextLine() 都是 Java Scanner 类的方法,用于检查输入流中是否还有下一个标记或行。它们之间的区别在于:
hasNext() 检查下一个标记(token),也就是以空格、制表符或换行符为分隔符的一个单词。如果输入流中还有下一个标记,则返回 true;否则返回 false。
hasNextLine() 检查下一行是否存在。如果输入流中还有下一行,则返回 true;否则返回 false。
因此,hasNext() 和 hasNextLine() 的主要区别在于它们检查的输入单元不同,前者检查标记,后者检查行。
一般来说,如果需要逐个读取每个单词,可以使用 hasNext() 方法;如果需要逐行读取每一行文本,可以使用 hasNextLine() 方法

next(); 这个函数会扫描从有效字符起到空格,Tab,回车等结束字符之间的内容并作为String返回。
nextLine(); 方法的结束符只是Enter键,它可以得到带空格的字符串的,即使你什么都没输入直接回车他也会输出
next();什么都不输入直接敲回车不会返回,而nextLine()即使不输入东西直接敲回车也会返回。

nextInt()只读取数值,读取完后 没有读取并且光标放在本行。

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String name = in.nextLine();//接收一个字符串,可以加除Enter以外的所有符号,包括空格和Tab
        String input = in.next();
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextInt()) { // 注意 while 处理多个 case
            int a = in.nextInt();
            int b = in.nextInt();
            System.out.println(a + b);
        }
        Scanner scan=new Scanner(System.in);
		int i = scan.nextInt();
		double d = scan.nextDouble();

    }
}

System.out.println

System.out.println(a+" , "+b); //通过“+”对字符串进行拼接

System.out.printf(“%d,%d”,a,b); //通过占位符,打印多个变量
System.out.printf(“%d,%d\n”,a,b); // 用\n来换行
占位符介绍(printf支持的格式):

%c        单个字符 
%d        十进制整数 
%f        十进制浮点数 
%o        八进制数 
%s        字符串 
%u        无符号十进制数 
%x        十六进制数 
%%        输出百分号% 

遍历方式

    /*数组结构的三种循环遍历效率对比*/
    @org.junit.Test
    public void test13(){
        List<Integer> list = new ArrayList<>(10000000);
        for(int i=0;i<1000;i++){
            list.add(i);
        }
        /*普通for循环*/
        long a = System.currentTimeMillis();
        int size = list.size();
        for(int i=0;i<size;i++){
            System.out.println(list.get(i));
        }
        Long b = System.currentTimeMillis();
        /*增强for循环*/
        long c = System.currentTimeMillis();
        for(Integer i : list){
            System.out.println(i);
        }
        long d = System.currentTimeMillis();
        /*迭代器*/
        Iterator iterator = list.iterator();
        long e = System.currentTimeMillis();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        long f = System.currentTimeMillis();
        System.out.println("普通for循环耗时:"+(b-a)+"--ms");
        System.out.println("增强for循环耗时:"+(d-c)+"--ms");
        System.out.println("迭代器耗时:"+(f-e)+"--ms");
    }

Integer

valueOf()包含包含3个相互重载的具体方法。

Integer.valueOf("1a", 16);//将1a解释为10进制数
Integer.valueOf("123")//即Integer.valueOf("123",10)返回十进制整数123
Integer integer = Integer.valueOf(6)//常用的创建Integer对象的方法

String.valueOf()

提到valueOf,这还有个String.valueOf()
(1)由基本数据型态转换成String

1String.valueOf(boolean b) :boolean 变量 b 转换成字符串 
(2String.valueOf(char c) :char 变量 c 转换成字符串 
(3String.valueOf(char[] data) :char 数组 data 转换成字符串 
(4String.valueOf(char[] data, int offset, int count) :char 数组 data 中 由 data[offset] 开始取 count 个元素 转换成字符串 

(5String.valueOf(double d) :double 变量 d 转换成字符串 
(6String.valueOf(float f) :float 变量 f 转换成字符串 
(7String.valueOf(int i) :int 变量 i 转换成字符串 
(8String.valueOf(long l) :long 变量 l 转换成字符串 
(9String.valueOf(Object obj) : 将 obj 对象转换成 字符串, 等于 obj.toString() 

(2)String 转换成 数字的基本数据型态
由 String 转换成 数字的基本数据型态 ,大多需要使用基本数据型态的包装类别
比如说 String 转换成 byte ,可以使用 Byte.parseByte(String s) ,这一类的方法如果无法将 s 分析 则会丢出 NumberFormatException

1byte : Byte.parseByte(String s) : 将 s 转换成 byte2Byte.parseByte(String s, int radix) : 以 radix 为基底 将 s 转换为 byte ,比如说 Byte.parseByte("11", 16) 会得到 173double : Double.parseDouble(String s) : 将 s 转换成 double4float : Double.parseFloat(String s) : 将 s 转换成 float5int : Integer.parseInt(String s) : 将 s 转换成 int6long : Long.parseLong(String s)

1.Map基本操作

Map<String, Integer> map这是声明Map对象指明键值对类型为String,
Map<String, Integer> map = new HashMap<>();创建一个实例并赋值给map

 Map<String, List<String>> map = new HashMap<String, List<String>>();//value为一个String的列表

定义:Map<Integer,Integer> map= new HashMap<>();
添加:map.put(‘aa’,‘aaa’)
访问: map.get(‘aa’) 方法来获取 key 对应的 value:
删除:map.remove(‘aa’)
计算大小:map.size()
迭代:map.keySet()、map.values()
map.containsKey(‘aa’) 方法检查 hashMap 中是否存在指定的 key 对应的映射关系。存在返回 true,否则返回 false。

Map<Character, Character> pairs = new HashMap<Character, Character>()//单个字符
Map<Integer,Integer> map= new HashMap<>();
 	// 输出 key 和 value
        for (Integer i : map.keySet()) {
            System.out.println("key: " + i + " value: " + map.get(i));
        }
   // 返回所有 value 值
        for(String value: map.values()) {
          // 输出每一个value
          System.out.print(value + ", ");
        }      
 map.put(num, stack.isEmpty() ? -1 : stack.peek());//先判断T/F再取值

1.1 map的value值转List

ArrayList<List<String>>(map.values());

1.2 Map.Entry

Map.entrySet() 这个方法返回的是一个Set<Map.Entry<K,V>>,Map.Entry 是Map中的一个接口,他的用途是表示一个映射项(里面有Key和Value),而Set<Map.Entry<K,V>>表示一个映射项的Set。Map.Entry里有相应的getKey和getValue方法,即JavaBean,让我们能够从一个项中取出Key和Value。

Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");

//遍历HashMap方式:
//第一种:普遍使用,二次取值
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遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
 System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}




HashSet(需要找是否已经包含了的时候用)

里面的元素无序,由于无序所以元素依旧是不能重复的,而且只能用for-each循环或迭代器

HashSet<String> set = new HashSet<String>();//定义
set.add("Tom");//添加
set.size();
set.isEmpty();
set.clear();//清除集合set中所有元素
boolean flag = set.contains("Tom");//将contains()判断结果赋给flag
boolean flag = set.remove("Tom");//将set集合中“Tom”元素除去并将是否成功的布尔值赋给flag

for (String name : set) {
	System.out.println(name);
}

Iterator<String> iterator = set.iterator();//创建Iterator<>对象
while(iterator.hasNext()) {
	System.out.println(iterator.next());
}


2.List操作

定义:

List<String> list = new ArrayList<String>();
List<List<Integer>> ret = new ArrayList<List<Integer>>();
//还可以创建保存多个数组的list
List<int[]> list = new ArrayList<int[]>();
List<String> list = new ArrayList<String>();
//添加元素.
list.add("Tom");
list.add("Jam");
list.add("Alix");

//获取元素.
String str = list.get(0);

//删除元素.
list.remove(1);
list.remove("Alix");

//遍历元素.
for (String s: list) {
    System.out.println(s);
}
 //判断某一个元素是否在list中
list.contains(name)
 //根据索引改变list中某一个值.
list.set(0, "Tom");
//返回元素值等于2的索引.
System.out.println(list.indexOf(2));
 //利用subList()截取, 然后给num.
 num = list.subList(1, 4);
 //判断是否为空
 arrayList.isEmpty()
  //转化成iterator对象.
Iterator it = arrayList.iterator();
 while(it.hasNext) {
     Object obj = it.next();
     System.out.println(obj);
 }

list的函数

list转为String

String str = "";
str = list.toString();

list转为数组

String[] str = list.toArray();
for (String s: str) {
    System.out.println(str);
}

list排序功能

Collections.sort(list);//list排序

list对应k与i位置的元素交换

Collections.swap(list,k,i);

数组的函数

数组排序

Arrays.sort(arr);//数组排序
//自定义排序方式
Arrays.sort(arr,new Comparator<int[]>(){//这个list里面是一个各个数组
	public int compare(int[] a,int[] b){//前-后是升序,后-前是降序
		return a[0]-b[0];//数据的[0]下标数据按照从小到大排序
	}
});

但是这种重写方式不能作用于基本数据类型(int、double…)。那就把int变成包装类(Integer、Double、Float…)就行

数组填充

int array[] = new int[6];
Arrays.fill(array, 100);//将数组填满100
Arrays.fill(array, 3, 6, 50);//[3,6)左闭右开区间填充50

Arrays.toString(strArr);数组转String:将数组转换成String类型输出的,传入的参数可以是boolean,byte,char,double,float,int,long,Object,short类型的数组。


int[] intArray = { 1, 4, 6, 7, 8, 9, 10 };
// 使用Arrays的toString方法打印出数组
System.out.println(Arrays.toString(intArray));
//[1, 4, 6, 7, 8, 9, 10]这里的数字其实是String类型的

将char[]数组直接new成String
cc=[‘a’,‘b’,‘c’]->str=“abc”

char[] cc = new char[n];
String str  = new String(cc);

对一个已有的数组进行截取复制,复制出一个左闭右开区间的数组:

Arrays.copyOfRange(preorder,1,i+1);

2.1 list和数组的区别

数组:
固定长度的容器,可以在其中存储同一类型的数据。数组在Java中是一个对象,可以通过索引访问其中的元素。
定义一个数组:

数据类型[] 数组名 = new 数据类型[数组长度];
int[] a = new int[5];
String str = new String[5];  str[0]='aa'; str[1]='bb';

数组定义时赋值
int[] ary1 = {1,2,3};//一维数组
int next[][]={{0,1},{1,0},{0,-1},{-1,0}};//二维数组

list:
List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。
实现List接口的常用类有LinkedList,ArrayList,Vector和Stack
(1)LinkedList实现了List接口,允许null元素。LinkedList底层采用了双向链表来存储数据,每个节点都存储着上一个节点和下一个节点的地址以及本节点的数据。
此外LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。

(2)ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList底层采用动态数组的存储方式,遍历效率非常高,ArrayList是线程不安全的。
size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。
每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。

ArrayList和LindedList的区别:

  1. ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
  2. 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
  3. 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

总结:
1、如果涉及到堆栈、队列等操作,应该考虑使用List,对于需要快速插入、删除的元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。
2、如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。
3、要特别注意对哈希表的操作,作为key的对象要正确复写equals和hashCode方法。
4、尽量返回接口而非实际的类型,如返回**List而非ArrayList,**这样如果以后需要将ArrayList换成LinkedList时,客户端代码不用改变。这就是针对抽象编程。

数组,List互相转换

(1)数组转换成 List 集合:
Arrays.asList(strArray) 方式,将数组转换List后,不能对List增删,只能查改,否则抛异常。

import java.util.Arrays;

// 转换数组对象
Long[] arr = new Long[]{10L, 20L, 30L};
List<Long> list1 = Arrays.asList(arr);

// 转换数组常量
List<String> list2 = Arrays.asList("123", "456", "789");

要想能修改可以这种:

private void testArrayCastToListEfficient(){
	String[] strArray = new String[2];
	ArrayList< String> arrayList = new ArrayList<String>(strArray.length);//创建一个ArrayList
	Collections.addAll(arrayList, strArray);//把值赋过去
	arrayList.add("1");
	System.out.println(arrayList);
}

(2)List 集合转数组
.toArray

// 方式1(推荐)
Long[] array = list.toArray(new Long[0]);//10L, 20L, 30L

List<int[]> list = new ArrayList<int[]>();这个list里面是数组{[1,2],[2,3]}
int[][] arr = list.toArray(new int[n][];)
// 方式2
String[] array = (String[]) list.toArray();

2.2栈和队列

队列的实现—利用Queue接口
堆栈的实现—利用Deque接口
使用ArrayDeque类实例化队列和栈
队列:

Queue<String> queue = new LinkedList<String> ();//队列定义
   queue.offer("x");//增加
   queue.offer("u");
   queue.offer("e");
   while(!queue.isEmpty()){//判断是否为空
       System.out.print(queue.poll()+" ");//移除
   }

堆栈:

Deque<String> stack= new LinkedList<String>();//堆栈
    stack.push("x");
    stack.push("u");
    stack.push("e");
    while(!stack.isEmpty()){
        System.out.print(stack.pop());//e
    }
    System.out.println(stack.size());//栈中含有的元素  5
    System.out.println(stack.search(2));//返回从栈顶往前数第size()-i(i为下表)个元素  4
    /*System.out.println(stack.peek());//查看拿到栈顶元素 不删除  结果为20
    *//*System.out.println(stack.pop());//出栈  删除栈顶元素  20


使用ArrayDeque类实例化队列和栈:

该类是Deque接口的大小可变数组的实现。数组双端队列没有容量限制;它们可根据需要增加以支持使用。它们不是线程安全的;在没有外部同步时,它们不支持多个线程的并发访问。禁止 null 元素。此类很可能在用作堆栈时快于 Stack,在用作队列时快于 LinkedList
操作 队列方法:
插入 offer(e)
移除 poll()
检查 peek()
操作 堆栈方法:
插入 push(e)
移除 pop()
检查 peek()返回栈顶的元素但不移除它。

但Stack的pop方法是会移除的。

new一个ArrayDeque对象 既能当堆栈又能当队列。

ArrayDeque<String> stack = new ArrayDeque<String> ();
stack.push("x");
stack.push("u");
stack.push("e");
while(!stack.isEmpty()){
    System.out.print(stack.pop());
}

PriorityQueue

PriorityQueue类是一种队列数据结构实现,其中根据优先级处理对象。它与遵循FIFO(先进先出)算法的标准队列不同。
在优先级队列中,添加的对象根据其优先级。默认情况下,优先级由对象的自然顺序决定。队列构建时提供的比较器可以覆盖默认优先级。
它能够在 O(log n) 的时间复杂度内实现元素的插入和删除操作,并且能够自动维护队列中元素的优先级顺序
作用:维护一组数据的排序,使得取出数据时可以按照一定的优先级顺序进行,当我们调用 poll() 方法时,它会从队列的顶部弹出最高优先级的元素。
大小关系:元素大小的评判可以通过元素本身的自然顺序(natural ordering),也可以通过构造时传入的比较器(Comparator,或者元素自身实现 Comparable 接口)来决定。默认为小顶堆

PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(); //默认小顶堆
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(11,new Comparator<Integer>(){ //大顶堆
    @Override
    public int compare(Integer i1,Integer i2){
        return i2-i1;
    }
});

以非INteger而是类为例子

//创建一个比较器
Comparator<Person2> cp = new Comparator<Person2>() {
    @Override
    public int compare(Person2 o1, Person2 o2) {
        //若为o1.getAge()-o2.getAge():按照age升序  从小到大
        return o2.getAge()-o1.getAge();//按照age降序 从大到小
    }
};

PriorityQueue 的底层是基于堆实现的,因此在数据量比较大时,使用 PriorityQueue 可以获得较好的时间复杂度。

  1. add()和 offer()
    add(E e)和offer(E e)的语义相同,都是向优先队列中插入元素,只是Queue接口规定二者对插入失败时的处理不同,前者在插入失败时抛出异常,后则则会返回false。对于PriorityQueue这两个方法其实没什么差别。

  2. element()和 peek()
    element()和peek()的语义完全相同,都是获取但不删除队首元素,也就是队列中权值最小的那个元素,二者唯一的区别是当方法失败时前者抛出异常,后者返回null。

  3. remove()和 poll()
    remove()和poll()方法的语义也完全相同,都是获取并删除队首元素,区别是当方法失败时前者抛出异常,后者返回null。

// 创建 PriorityQueue 对象
PriorityQueue<String> priorityQueue = new PriorityQueue<>();//默认是小顶堆

// 添加元素到 PriorityQueue
priorityQueue.offer("a");
priorityQueue.offer("b");
priorityQueue.offer("c");

// 打印 PriorityQueue 中的元素
System.out.println("PriorityQueue 中的元素:");
while (!priorityQueue.isEmpty()) {
    System.out.print(priorityQueue.poll() + " ");
}

输出:
PriorityQueue 中的元素:
a b c
  1. 实际应用中
    PriorityQueue 也经常用于实现 Dijkstra 算法、Prim 算法、Huffman 编码等算法。
    Dijkstra算法是一种用于计算带权图中的最短路径的算法。该算法采用贪心的策略,在遍历图的过程中,每次选取当前到源点距离最短的一个顶点,并以它为中心进行扩展,更新其他顶点的距离值。经过多次扩展,可以得到源点到其它所有顶点的最短路径。
    Prim算法是一种用于求解最小生成树的算法,可以在加权连通图中找到一棵生成树,使得这棵生成树的所有边的权值之和最小。该算法从任意一个顶点开始,逐渐扩展生成树的规模,每次选择一个距离已生成树最近的顶点加入到生成树中。
    Huffman编码是一种基于霍夫曼树的压缩算法,用于将一个字符串转换为二进制编码以进行压缩。该算法的主要思想是通过建立霍夫曼树,将出现频率较高的字符用较短的编码表示,而出现频率较低的字符用较长的编码表示,从而实现对字符串的压缩。在解压缩时,根据编码逐步解析出原字符串

3.String,char转换

char表示字符,定义时用单引号,只能存储一个字符
而String表示字符串,定义时用双引号,可以存储一个或多个字符

char[] row = new char[n];
String str = new String();
String[] strs = new String[n];

String需要转char 列表

“apple”->[‘a’,‘p’,‘p’,‘l’,‘e’]

char[] arr = str.toCharArray();//将String中的字母转成char放列表里
Arrays.sort(arr);//将字母排序

char列表转String

String key = new String(arr);

charAt()方法

java中,charAt()方法用于返回指定索引处的字符
因为String不能s[i]这样访问字符,所以只能s.charAt(i)

String s = "helloworld";
char what =s.charAt(5);//o

String的其他方法

for(int i=0;i<str.length();i++){
	Character.isDigit(str.charAt(i))用来判断字符是否是数字
}
String currentString = "";

StringBuffer ans=new StringBuffer();
ans.append(currentString);向后添加
currentString = ans.toString();转为String

StringBuilder temp = new StringBuilder();
temp.append(currentString);向后添加
currentString = temp.toString();转为String

StringBuilder可以用字符翻转

String original = "Hello, World!";
StringBuilder sb = new StringBuilder(original);
String reversed = sb.reverse().toString();

StringBuilder 删除字符

 StringBuilder sb = new StringBuilder("Hello, World!");
// 删除指定位置上的字符,例如删除位于索引5的字符('o')
sb.deleteCharAt(5); // 返回新的StringBuilder对象,sb原地修改
System.out.println(sb.toString()); // 输出: Hello, Wrld!

// 删除从索引2开始到索引4的字符,包括索引2,不包括索引4
sb.delete(2, 4); // 返回新的StringBuilder对象,sb原地修改
System.out.println(sb.toString()); // 输出: Hl, Wrld!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值