Java 超详细讲解数据结构的应用

目录
  • 一.bfs
  • 二.双端队列
  • 三.算法题
    • 1.kotori和迷宫
    • 2.小红找红点
    • 3.小红玩数组 

一.bfs

bfs(广度优先搜索),类似二叉树的层序遍历,利用队列完成。一般用于求最短路。

图的最短路问题:

给定一个无向图,每条边的长度都是1。求1号点到x号点的最短距离。 顶点数n  边数为m

q次询问  输入x 输出1到x的最短距离。 若1号点到x不连通,则输出-1

二.双端队列

双端队列的应用(区间翻转):

对于长度为n的数组,给定一个长度为m的区间,区间初始位置为a[1]到a[m]。

3种操作:

  • 区间右移(最右端不会超过a[n])
  • 区间左移(最左端不会超过a[n])
  • 区间内所有数翻转。

q次操作后请你还原数组。

三.算法题

1.kotori和迷宫

难度

知识点:bfs

首先找到k字母,然后从k字母位置开始bfs。bfs过程中即可得到k到每个e的最短路程。(要注意走过的e不可继续往下走)

题目描述:

kotori在一个n*m迷宫里,迷宫的最外层被岩浆淹没,无法涉足,迷宫内有k个出口。kotori只能上下左右四个方向移动。她想知道有多少出口是她能到达的,最近的出口离她有多远?

输入描述:

第一行为两个整数n和m,代表迷宫的行和列数 (1≤n,m≤30)

后面紧跟着n行长度为m的字符串来描述迷宫。'k'代表kotori开始的位置,'.'代表道路,'*'代表墙壁,'e'代表出口。保证输入合法。

输出描述:

若有出口可以抵达,则输出2个整数,第一个代表kotori可选择的出口的数量,第二个代表kotori到最近的出口的步数。(注意,kotori到达出口一定会离开迷宫)

若没有出口可以抵达,则输出-1。

示例1

输入

6 8

e.*.*e.*

.**.*.*e

..*k**..

***.*.e*

.**.*.**

*......e

输出

2 7

说明

可供选择坐标为[4,7]和[6,8],到kotori的距离分别是8和7步。

import java.util.*;
import java.io.*;
public class Main{
  public static void main(String[] args) throws IOException{
    BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
    String[] s1 = bf.readLine().split(" ");
    int n = Integer.parseInt(s1[0]);
    int m = Integer.parseInt(s1[1]);
    //建立地图、标记图
    char[][] maze = new char[n][m];
    boolean[][] visited = new boolean[n][m];
    //纪录步数
    int[][] dis = new int[n][m];
    //纪录初始的坐标
    int ki = 0, kj = 0;
    for(int i = 0; i < n; i++){
      String s = bf.readLine();
      for(int j = 0; j < m; j++){
         dis[i][j] = Integer.MAX_VALUE;
         char c = s.charAt(j);
         maze[i][j] = c;
         if(c == 'k'){
          ki = i;
          kj = j;
        }
      }
    }

    int count = 0, min = Integer.MAX_VALUE;
    Queue<Integer> queue = new ArrayDeque<>();
    //二维数组的性质,保存了坐标,并且节省了空间
    queue.add(ki * m + kj);
    visited[ki][kj] = true;
    dis[ki][kj]= 0;
    while(!queue.isEmpty()){
      int temp = queue.poll();
      int tempi = temp / m, tempj = temp % m;
      //支持八个方向的移动或者不移动(但是因为Math.abs(i - j) == 1限定了绝对值为1,所以变成了四个方向)
      for(int i = -1; i <= 1; i++){
        for(int j = -1; j <= 1; j++){
          if(Math.abs(i - j) == 1 && tempi + i >= 0 && tempi + i < n && tempj + j >= 0 && tempj + j < m && !visited[tempi + i][tempj + j]){
            if(maze[tempi + i][tempj + j] == '.'){
              visited[tempi + i][tempj + j] = true;
              dis[tempi + i][tempj + j] = dis[tempi][tempj] + 1;
              queue.add((tempi + i) * m + (tempj + j));
            }
            if(maze[tempi + i][tempj + j] == 'e'){
              visited[tempi + i][tempj + j] = true;
              dis[tempi + i][tempj + j] = dis[tempi][tempj] + 1;
              min = Math.min(min, dis[tempi][tempj] + 1);
              count++;
            }
          }
        }
      }
    }
    if(count == 0) System.out.print(-1);
    else System.out.print(count + " " + min);
  }
}

思考:队列是怎么实现bfs的?

1.起始点入队-->2.将起始点四个方向的可达点入队-->3.起始点出队。以此循序依次访问队列中的元素。

2.小红找红点

难度

知识点:bfs,多源最短路

多源最短路的求法:在bfs开始之前将所有点都扔进队列,然后开始bfs即可。

题目描述:

小红拿到了一张无向图,有 n 个顶点和 m 条边。每条边的长度为 1 。 

小红给一些顶点染成了红色。她想知道,对于每个顶点,到附近最近的红色点的距离为多少?

输入描述:

第一行输出两个正整数 n 和 m ,用空格隔开。分别代表顶点数和边数。

第二行输入一个长度为 n 的字符串,代表每个顶点的染色情况。第 i 个字符为 'R' 代表被染成红色,为 'W' 代表未被染色。

接下来的 m 行,每行两个正整数 x 和 y ,代表 x 和 y 有一条无向边相连。

不保证图是整体连通的。不保证没有重边和自环。

1<=n,m<=10^5

输出描述:

输出一行 n 个整数,代表从 1 到 n 每个顶点到最近的红色顶点的距离。若对于某点而言无论如何都走不到红色顶点,则输出 -1 。

示例1:

输入

5 5

RWWRW

1 2

3 3

1 2

2 5

1 4

输出

0 1 -1 0 2

说明

样例的图如上所示。

import java.util.*;
import java.io.*;

public class Main{
    static ArrayList<Integer>[] g;
    static String[] strings;
    static int[] visited;
    static int[] dis;

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] firstLine = br.readLine().split(" ");
        int n = Integer.parseInt(firstLine[0]);
        int m = Integer.parseInt(firstLine[1]);
        g = new ArrayList[n+1];
        visited = new int[n+1];
        dis= new int[n+1];
        for (int i=1;i<n+1;i++) {
            g[i] = new ArrayList<Integer>();
        }
        //一个字符一个字符的读取
        strings = br.readLine().split("");
        for (int i=0;i<m;i++) {
            //描绘双向图
            String[] temp = br.readLine().split(" ");
            int x = Integer.parseInt(temp[0]);
            int y = Integer.parseInt(temp[1]);
            g[x].add(y);
            g[y].add(x);
        }
        //g[x]代表当前点 g[x].get(i)代表所连的线
        Queue<Integer> queue = new ArrayDeque<>();
        for(int i=1;i<=n;i++){
            if(strings[i-1].equals("R")){
                queue.add(i);
                visited[i]=1;
            }
        }
        while(!queue.isEmpty()){
            int temp=queue.remove();
            for(int i=0;i<g[temp].size();i++){
                if(visited[g[temp].get(i)]==0){
                    visited[g[temp].get(i)]=1;
                    dis[g[temp].get(i)]=dis[temp]+1;
                    queue.add(g[temp].get(i));
                }
            }
        }
        for(int i=1;i<=n;i++){
            if(visited[i]==0)System.out.print("-1 ");
            else System.out.print(dis[i]+" ");
        }
    }
}

对照上一章的案例:小红点点点结合理解。  分别使用的dfs和bfs。

本题思想:先将红色的所有点都入队列,然后bfs。

这是一种逆向思维:不是所谓的从编号开始,并且所有走过的都不能在走了。

3.小红玩数组 

难度

知识点:双端队列

用一个双端队列来模拟过程,用一个变量来标记双端队列是否翻转过。

示例1:

输入

6 4

1 5 4 6 2 8

5

21323

输出

4 6 2 1 5 8

import java.io.*;
import java.util.*;
public class Main{
    static Deque<Integer> workQueue;
    public static void main(String[] args)throws IOException{
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        PrintWriter pw=new PrintWriter(System.out);
        String[] firstLine=br.readLine().split(" ");
        int total=Integer.parseInt(firstLine[0]);
        int size=Integer.parseInt(firstLine[1]);
        int[] arr=new int[total];
        String[] secondLine=br.readLine().split(" ");
        for(int i=0;i<total;i++){
            arr[i]=Integer.parseInt(secondLine[i]);
        }
        int L=0;
        int R=size-1;
        workQueue=new LinkedList<>();
        for(int i=0;i<size;i++){
            workQueue.offerLast(arr[i]);
        }
        int times=Integer.parseInt(br.readLine());
        String tries=br.readLine();
        int is=0;//0代表没有翻转!
        for(int i=0;i<times;i++){
            if(tries.charAt(i)=='1'){
                if(R==arr.length-1)
                    continue;
                R++;
                if(is==0){

                    workQueue.offerLast(arr[R]);
                    int tmp=workQueue.pollFirst();
                    arr[L]=tmp;

                }else{

                    workQueue.offerFirst(arr[R]);
                    int tmp=workQueue.pollLast();
                    arr[L]=tmp;

                }
                L++;
            }else if(tries.charAt(i)=='2'){
                if(L==0)
                    continue;
                L--;
                if(is==0){
                    workQueue.offerFirst(arr[L]);

                    arr[R]=workQueue.pollLast();

                }else{

                    workQueue.offerLast(arr[L]);
                    arr[R]=workQueue.pollFirst();

                }
                R--;
            }else{
                is=1-is;
            }
        }
        for(int i=0;i<L;i++){
            pw.print(arr[i]+" ");
        }
        if(is==0){
            while(!workQueue.isEmpty()) {
                pw.print(workQueue.pollFirst() + " ");
            }
        }else{
            while(!workQueue.isEmpty()) {
                pw.print(workQueue.pollLast() + " ");
            }
        }
        for(int i=R+1;i<arr.length;i++){
            pw.print(arr[i]+" ");
        }
        pw.flush();

    }
}

到此这篇关于Java 超详细讲解数据结构的应用的文章就介绍到这了,更多相关Java 数据结构内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java数据结构关于栈的实例应用

    此文章介绍关于顺序栈,链式栈的实例操作,括号匹配,表达式求值(后缀表达式) 1.声明一个栈接口SStack package ch05; public interface SStack <T>{ boolean isEmpty(); // 判断栈是否为空 void push(T x); // 元素x入栈 T pop(); // 出栈,返回栈顶元素 T peek(); // 返回栈顶元素,但不出栈 }  2. 定义顺序栈类SeqStack<T>,包括数据元素的对象数组和栈顶元素下标两个

  • java 数据结构中栈结构应用的两个实例

    java 数据结构中栈结构应用的两个实例 1.单词逆序. 要求从控制台读入一串字符,按回车结束输入,同时显示其逆序字符串. 对于颠倒顺序的操作,用栈来解决是很方便的.具体思想是把字符串中的每一个字符按顺序存入栈中,然后再一个一个的从栈中取出.这时就是按照逆序取出的字符串. // reverse.java // stack used to reverse a string // to run this program: C>java ReverseApp import java.io.*; //

  • Java 数据结构之堆的概念与应用

    目录 什么是堆 堆的类型 小根堆 大根堆 堆的基本操作:创建堆 堆的时间复杂度和空间复杂度 堆的应用-优先级队列 概念 优先级队列基本操作 入优先级队列 出优先级队列首元素 java的优先级队列 堆的常见面试题 最后一块石头的重量 找到K个最接近的元素 查找和最小的K对数字 java数据结构的堆 什么是堆 堆指的是使用数组保存完全二叉树结构,以层次遍历的方式放入数组中. 如图: 注意:堆方式适合于完全二叉树,对于非完全二叉树若使用堆则会造成空间的浪费 对于根节点与其左右孩子在数组中的下标关系可表

  • Java 超详细讲解数据结构中的堆的应用

    目录 一.堆的创建 1.向下调整(以小堆为例) 2.创建堆 3.创建堆的时间复杂度 二.堆的插入和删除 1.堆的插入 2.堆的删除 三.堆的应用 1.堆排序 2.top-k问题 [求最小的K个数] 四.常用接口的介绍 1.PriorityQueue的特性 2.优先级队列的构造 一.堆的创建 1.向下调整(以小堆为例) 让parent标记需要调整的节点,child标记parent的左孩子(注意:parent如果有孩子一定先是有左孩子) 如果parent的左孩子存在,即:child < size,

  • Java 超详细讲解数据结构的应用

    目录 一.bfs 二.双端队列 三.算法题 1.kotori和迷宫 2.小红找红点 3.小红玩数组  一.bfs bfs(广度优先搜索),类似二叉树的层序遍历,利用队列完成.一般用于求最短路. 图的最短路问题: 给定一个无向图,每条边的长度都是1.求1号点到x号点的最短距离. 顶点数n  边数为m q次询问  输入x 输出1到x的最短距离. 若1号点到x不连通,则输出-1 二.双端队列 双端队列的应用(区间翻转): 对于长度为n的数组,给定一个长度为m的区间,区间初始位置为a[1]到a[m].

  • Java 超详细讲解数据结构中的堆的应用

    目录 一.堆的创建 1.向下调整(以小堆为例) 2.创建堆 3.创建堆的时间复杂度 二.堆的插入和删除 1.堆的插入 2.堆的删除 三.堆的应用 1.堆排序 2.top-k问题(求最小的K个数) 四.常用接口的介绍 1.PriorityQueue的特性 2.优先级队列的构造 一.堆的创建 1.向下调整(以小堆为例) 让parent标记需要调整的节点,child标记parent的左孩子(注意:parent如果有孩子一定先是有左孩子) 如果parent的左孩子存在,即:child < size, 进

  • Java超详细讲解多线程中的Process与Thread

    目录 进程和线程的关系 操作系统是如何管理进程的 并行和并发 创建线程的方法 串行执行和并发执行 Thread中的一次额重要方法 中断线程 线程等待 线程休眠(sleep) 进程和线程的关系 在操作系统中运行的程序就是进程,比如说QQ,播放器,游戏等等…程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念. 进程和线程都是为了处理并发编程这样的场景,但是进程有问题,频繁拆功创建和释放资源的时候效率低,相比之下,线程更轻量,创建和释放效率更高. 进程具有独立性,每个进程有各自独立

  • Java 超详细讲解设计模式之中的抽象工厂模式

    目录 抽象工厂模式 1.什么是抽象工厂 2.抽象工厂模式的优缺点 3.抽象工厂模式的结构与实现 4.抽象工厂方法模式代码实现 5.抽象工厂模式的应用场景 6.抽象工厂模式的扩展 抽象工厂模式 前面文章介绍的工厂方法模式中考虑的是一类产品的生产,比如案例中的百事可乐工厂只能生产百事可乐,可口可乐工厂只能生产可口可乐,也就是说:工厂方法模式只考虑生产同等级的产品. 1.什么是抽象工厂 在现实生活中许多工厂是综合型的工厂,能生产多种类)的产品,就拿案例里面的可乐来说,在节日的时候可能会有圣诞版的可乐,

  • Java 超详细讲解IO操作字节流与字符流

    目录 IO操作 字节流 FileInputStream FileOutputStream 字节流读写案例 字符流 FileReader FileWriter 字节流与字符流的区别 IO操作 字节流 java.io.InputStream 输入流,主要是用来读取文件内容的. java.io.OutputStream 输出流,主要是用来将内容字节写入文件的. FileInputStream 该流用于从文件读取数据,它的对象可以用关键字 new 来创建. 有多种构造方法可用来创建对象. 可以使用字符串

  • Java 超详细讲解设计模式之中的建造者模式

    目录 1.什么是建造者模式? 2.建造者模式的定义 3.建造者模式的优缺点 4.建造者模式的结构 5.建造者模式代码演示 6.建造者模式的应用场景 7.建造者模式和工厂模式的区别 1.什么是建造者模式? 我们知道在软件开发过程中有时需要创建一个很复杂的对象,通常由多个子部件按一定的步骤组合而成. 例如,比如我们在自己在组装一台计算机的时候,需要有 CPU.主板.内存.硬盘.显卡.机箱.显示器.键盘.鼠标等部件组装而成的.比如学校需要采购100台计算机,学校不可能自己把零件买过来自己组装,肯定是告

  • Java超详细讲解设计模式之一的工厂模式

    目录 工厂模式 1.简单工厂 1.1结构 1.2实现 1.3优缺点 1.4扩展 2.工厂方法 2.1结构 2.2实现 2.3优缺点 3.抽象工厂 3.1结构 3.2实现 3.3优缺点 4.模式扩展 4.1实现 工厂模式 在Java应用程序中对象无处不在,这些对象都需要进行创建,如果创建的时候直接new对象,那么如果我们要更换对象,所有new对象的地方都需要进行更改.违背了软件设计原则中的开闭原则.如果我们使用工厂生产对象,只需要在工厂中关注对象的改变即可,达到了与对象解耦的目的,工厂模式最大的特

  • Java 超详细讲解类的定义方式和对象的实例化

    目录 1.面对对象的初步认识 1.1什么是面向对象 1.2面向对象与面向过程 2.类的定义与使用 2.1简单认识类 2.2 类的定义格式 3.类的实例化 3.1什么是实例化? 3.2重点笔记 总结 1.面对对象的初步认识 1.1什么是面向对象 用面向对象的思想来涉及程序,更符合人们对事物的认知,对于大型程序的设计.扩展以及维护都非常友好. 1.2面向对象与面向过程 举一个买手机的例子 以面向对象的方式来处理买手机这件事的话,我们就不需要关注买手机的过程,具体手机怎么买,如何到手,用户不用去关心,

  • Java 超详细讲解对象的构造及初始化

    目录 如何初始化对象 构造方法 特性 默认初始化 就地初始化 如何初始化对象 我们知道再Java方法内部定义一个局部变量的时候,必须要初始化,否则就会编译失败 要让这串代码通过编译,很简单,只需要在正式使用a之前,给a设置一个初始值就好那么对于创造好的对象来说,我们也要进行相对应的初始化我们先写一个Mydate的类 public class MyDate { public int year; public int month; public int day; /** * 设置日期: */ pub

随机推荐