【数据结构】蓝桥杯常见习题(二)

简介: 【数据结构】蓝桥杯常见习题(二)

1.最大连续子段和


这段代码是一个求最大子数组和的算法,使用的是动态规划的思想。下面是代码的解释:

首先定义了一个整数数组arr,用于存储给定的一组数。然后定义了一个整数数组dp,用于存储以arr中每个元素为结尾的最大子数组和。接着将dp的第一个元素设置为0和arr的第一个元素的最大值。然后从第二个元素开始循环遍历数组dp,将当前元素的dp设置为 :前一个元素的dp 和 当前元素的arr之和 与 当前元素的arr 比较最大值。最后按升序对数组dp进行排序,最大子数组和即为dp的最后一个元素。

public class A {
public static void main(String[] args) {
    int arr[]= {-2,11,-4,13,-5,-2}; //定义一个数组arr
    int dp[]=new int[arr.length]; //定义一个数组dp,长度与arr相同
    System.out.println("arr:"+Arrays.toString(arr)); //输出arr数组
    System.out.println("-----------流程-----------"); //输出分割线
    dp[0]=Math.max(0, arr[0]); //dp[0]为arr[0]和0的最大值
    System.out.println("dp:"+Arrays.toString(dp)); //输出dp数组
    for (int i = 1; i < dp.length; i++) { //循环dp数组
        dp[i]=Math.max(dp[i-1]+arr[i], arr[i]); //dp[i]为dp[i-1]+arr[i]和arr[i]的最大值
        System.out.println("dp[i-1]+arr[i]:"+(dp[i-1]+arr[i])+"\narr[i]:"+arr[i]); //输出dp[i-1]+arr[i]和arr[i]
        System.out.println("dp:"+Arrays.toString(dp)); //输出dp数组
    }
    Arrays.sort(dp); //对dp数组进行排序
    System.out.println("-----------流程-----------"); //输出分割线
    System.out.println("最大字段和:"+dp[dp.length-1]); //输出dp数组中的最大值
}
arr:[-2, 11, -4, 13, -5, -2]
-----------流程-----------
dp:[0, 0, 0, 0, 0, 0]
dp[i-1]+arr[i]:11
arr[i]:11
dp:[0, 11, 0, 0, 0, 0]
dp[i-1]+arr[i]:7
arr[i]:-4
dp:[0, 11, 7, 0, 0, 0]
dp[i-1]+arr[i]:20
arr[i]:13
dp:[0, 11, 7, 20, 0, 0]
dp[i-1]+arr[i]:15
arr[i]:-5
dp:[0, 11, 7, 20, 15, 0]
dp[i-1]+arr[i]:13
arr[i]:-2
dp:[0, 11, 7, 20, 15, 13]
-----------流程-----------
最大字段和:20


分治法:

最大字段和(分治法,递归,Java)


2.LCS 最大公共子序列


例如:

S1={1,5,2,8,9,3,6},S2={5,6,8,9,3,7},其最大公共子序列为{5,8,9,3}。

为了找到两个字符串之间的最大公共子序列,我们可以使用动态规划。基本思想是创建一个矩阵,其中每个单元格表示到该点的最大公共子序列的长度。

我们从将矩阵的第一行和第一列初始化为0开始。然后,对于每个后续单元格,我们检查两个字符串中相应位置的字符是否匹配。如果匹配,则将当前单元格的左上角对角线上的值加1。如果不匹配,则取当前单元格上方和左侧单元格之间的最大值。

填充整个矩阵后,最长公共子序列的长度可以在右下角单元格中找到。


public class A {
public static void main(String[] args) {
    String s1="BDCABA";
    String s2="ABCBDAB";
    int dp[][]=new int[s1.length()+1][s2.length()+1];
    for (int i = 0; i < s1.length(); i++) {
        for (int j = 0; j < s2.length(); j++) {
            if(s1.charAt(i)==s2.charAt(j)) dp[i+1][j+1]=dp[i][j]+1;
            else dp[i+1][j+1]=Math.max(dp[i+1][j], dp[i][j+1]);
        }
    }
    for (int[] is : dp) {
        for (int i : is) {
            System.out.print(i+" ");
        }
        System.out.println();
    }
    System.out.println("最大公共子序列:"+dp[s1.length()][s2.length()]);
 }
}
0 0 0 0 0 0 0 0 
0 0 1 1 1 1 1 1 
0 0 1 1 1 2 2 2 
0 0 1 2 2 2 2 2 
0 1 1 2 2 2 3 3 
0 1 2 2 3 3 3 4 
0 1 2 2 3 3 4 4 
最大公共子序列:4


3.LIS 最长上升子序列


动态规划解决方案的基本思想是使用一个数组 dp 来跟踪输入数组中每个索引处的最长上升子序列的长度。我们将dp初始化为所有 1,因为任何索引处的最长上升子序列长度至少为 1(元素本身)。然后,我们遍历输入数组,并对于每个元素,我们遍历所有先前的元素并检查它们是否小于当前元素。如果是,我们将当前索引处的 dp更新为其当前值和前一个索引处的值加 1 的最大值。这意味着我们已经找到了以当前索引结尾的更长的上升子序列。最后,我们输出 dp 中的最大值,它表示输入数组中最长上升子序列的长度。


public class A {
public static void main(String[] args) {
    Scanner scanner=new Scanner(System.in);
    int n=scanner.nextInt(); //输入数组长度
    int arr[]=new int[n]; //定义数组
    for (int i = 0; i < arr.length; i++) {
        arr[i]=scanner.nextInt(); //输入数组元素
    }
    int dp[]=new int[arr.length]; //定义dp数组
    Arrays.fill(dp, 1); //初始化dp数组
    int j=0;
    for (int i = 1; i < arr.length; i++) {
        j=i-1;
    while (j>=0) {  
        if(arr[i]>arr[j]) { //如果当前元素大于前面的元素
            dp[i]=Math.max(dp[i], dp[j]+1); //更新dp数组
        }
        j--;
    }
}
    System.out.println(Arrays.toString(dp)); //输出dp数组
    Arrays.sort(dp); //对dp数组进行排序
    System.out.println(dp[dp.length-1]); //输出dp数组中的最大值
}
}
输入:
7
1 5 2 3 11 7 9
输出:
[1, 2, 2, 3, 4, 4, 5]
5


4.数塔


【动态规划】——数塔(java版,超详图解)


5.最大子矩阵和


知识点:前缀和+动态规划【最大字段和】


【蓝桥杯-筑基篇】前缀和

了解决这个问题,我们首先读入一个n x n的矩阵,并计算每列的前缀和。然后,对于每对起始和结束列,我们计算它们之间的子矩阵和。

接下来,我们使用动态规划来找到每列的最大子段和,并相应地更新最大子矩阵和。最后,我们输出最大子矩阵和。

//读入一个n*n的矩阵
//计算每一列的前缀和
//对于每一列的起始和结束位置,计算出这两列之间的子矩阵和
//用dpi表示以第i列为结尾的最大子段和
//对于每一列,计算以该列为结尾的最大子段和,并更新ans
//输出最大子矩阵和
public class B {
  public static void main(String[] args) {
    Scanner scanner=new Scanner(System.in);
    int n=scanner.nextInt();
    int[][] g=new int[n+1][n+1];
    for (int i = 1; i < g.length; i++) {
      for (int j = 1; j < g.length; j++) {
        g[i][j]=scanner.nextInt();
        g[i][j]=g[i][j]+g[i-1][j]; // 计算每一列的前缀和
      }
    }
    for (int[] is : g) {
      //输出前缀和数组
      System.out.println(Arrays.toString(is));
    }
    int ans=Integer.MIN_VALUE;
      for (int start = 1; start < g.length; start++) {
        for (int end = 1; end < g.length; end++) {
          int dpi=0;
          for (int col = 1; col < g.length; col++) {
            int ai=g[end][col]-g[start-1][col]; // 计算出这两列之间的子矩阵和
            dpi=Math.max(dpi+ai, ai); // 计算以该列为结尾的最大子段和
            ans=Math.max(ans, dpi); // 更新ans
          }
        }
      }
      System.out.println("--最大子矩阵和--:"+ans); // 输出最大子矩阵和
  }
}
4
0 -2  -7  0 
9  2  -6  2 
-4  1  -4  1
-1  8  0  -2 
[0, 0, 0, 0, 0]
[0, 0, -2, -7, 0]
[0, 9, 0, -13, 2]
[0, 5, 1, -17, 3]
[0, 4, 9, -17, 1]
--最大子矩阵和--:15


6.背包问题


①01背包问题


解题思路:使用动态规划算法解决01背包问题,首先输入物品数量和背包容量,然后输入每个物品的重量和价值,接着使用二重循环遍历物品和背包容量,如果当前背包容量大于等于当前物品重量,则可以选择将该物品放入背包,此时背包的价值为dpi-1]+val[i],否则背包的价值为dpi-1,最后输出动态规划数组即可


/**
 * 01背包问题
 * wt: 物品重量
 * val: 物品价值
 * dp: 动态规划数组
 */
public class C {
  public static void main(String[] args) {
    Scanner scanner=new Scanner(System.in);
    int n=scanner.nextInt(); // 物品数量
    int m =scanner.nextInt(); // 背包容量
    int wt[]=new int[n+1]; // 物品重量数组
    int val[]=new int[n+1]; // 物品价值数组
    int dp[][]=new int[n+1][m+1]; // 动态规划数组
    for (int i = 1; i < wt.length; i++) {
      wt[i]=scanner.nextInt(); // 输入物品重量
      val[i]=scanner.nextInt(); // 输入物品价值
    }
    for (int i = 1; i < wt.length; i++) {
      for (int j = 1; j <= m; j++) {
        if(j-wt[i]>=0) {
          dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-wt[i]]+val[i]); // 动态规划
        }
        else dp[i][j]=dp[i-1][j]; // 动态规划
      }
    }
    for (int[] is : dp) {
      System.out.println(Arrays.toString(is)); // 输出动态规划数组
    }
  }
}


②完全背包

// 本题为完全背包问题,采用动态规划求解。时间复杂度为O(nW),空间复杂度为O(nW)。
public class C {
  public static void main(String[] args) {
    int[] weights = {2, 3, 4, 5}; // 物品重量
    int[] values = {3, 4, 5, 6}; // 物品价值
    int capacity = 8; // 背包容量
    int result = completeKnapsack(capacity,weights, values); // 调用函数
    System.out.println("Maximum value: " + result); // 输出结果
    }
  public static int completeKnapsack(int W, int[] w, int[] v) {
      int n = w.length; // 物品数量
      int[][] dp = new int[n+1][W+1]; // 初始化动态规划数组
      for (int i = 0; i <= n; i++) {
          dp[i][0] = 0; // 初始化
      }
      for (int j = 0; j <= W; j++) {
          dp[0][j] = 0; // 初始化
      }
      for (int i = 1; i <= n; i++) {
          for (int j = 1; j <= W; j++) {
            for(int k=0;k<=(j/w[i-1]);k++) {
              dp[i][j] = Math.max(dp[i][j], dp[i-1][j-k*w[i-1]]+k*v[i-1]); // 状态转移方程
            }
          }
      }
      return dp[n][W]; // 返回最大价值
  }
}


目录
相关文章
|
23天前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
134 77
|
23天前
|
存储 C++
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
【数据结构——树】哈夫曼树(头歌实践教学平台习题)【合集】目录 任务描述 相关知识 测试说明 我的通关代码: 测试结果:任务描述 本关任务:编写一个程序构建哈夫曼树和生成哈夫曼编码。 相关知识 为了完成本关任务,你需要掌握: 1.如何构建哈夫曼树, 2.如何生成哈夫曼编码。 测试说明 平台会对你编写的代码进行测试: 测试输入: 1192677541518462450242195190181174157138124123 (用户分别输入所列单词的频度) 预
56 14
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
|
23天前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
40 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
23天前
|
算法 C++
【C++数据结构——查找】二叉排序树(头歌实践教学平台习题)【合集】
【数据结构——查找】二叉排序树(头歌实践教学平台习题)【合集】 目录 任务描述 相关知识 测试说明 我的通关代码: 测试结果: 任务描述 本关任务:实现二叉排序树的基本算法。 相关知识 为了完成本关任务,你需要掌握:二叉树的创建、查找和删除算法。具体如下: (1)由关键字序列(4,9,0,1,8,6,3,5,2,7)创建一棵二叉排序树bt并以括号表示法输出。 (2)判断bt是否为一棵二叉排序树。 (3)采用递归方法查找关键字为6的结点,并输出其查找路径。 (4)分别删除bt中关键
49 11
【C++数据结构——查找】二叉排序树(头歌实践教学平台习题)【合集】
|
23天前
|
存储 人工智能 算法
【C++数据结构——图】最短路径(头歌教学实验平台习题) 【合集】
任务描述 本关任务:编写一个程序,利用Dijkstra算法,实现带权有向图的最短路径。 相关知识 为了完成本关任务,你需要掌握:Dijkst本关任务:编写一个程序,利用Dijkstra算法,实现带权有向图的最短路径。为了完成本关任务,你需要掌握:Dijkstra算法。带权有向图:该图对应的二维数组如下所示:Dijkstra算法:Dijkstra算法是指给定一个带权有向图G与源点v,求从v到G中其他顶点的最短路径。Dijkstra算法的具体步骤如下:(1)初始时,S只包含源点,即S={v},v的距离为0。
50 15
|
23天前
|
Java C++
【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
40 12
|
23天前
|
C++
【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
本文档介绍了如何根据二叉树的括号表示串创建二叉树,并计算其结点个数、叶子结点个数、某结点的层次和二叉树的宽度。主要内容包括: 1. **定义二叉树节点结构体**:定义了包含节点值、左子节点指针和右子节点指针的结构体。 2. **实现构建二叉树的函数**:通过解析括号表示串,递归地构建二叉树的各个节点及其子树。 3. **使用示例**:展示了如何调用 `buildTree` 函数构建二叉树并进行简单验证。 4. **计算二叉树属性**: - 计算二叉树节点个数。 - 计算二叉树叶子节点个数。 - 计算某节点的层次。 - 计算二叉树的宽度。 最后,提供了测试说明及通关代
40 10
|
23天前
|
算法 C++
【C++数据结构——图】最小生成树(头歌实践教学平台习题) 【合集】
【数据结构——图】最小生成树(头歌实践教学平台习题)目录 任务描述 相关知识 测试说明 我的通关代码: 测试结果:【合集】任务描述 本关任务:编写一个程序求图的最小生成树。相关知识 为了完成本关任务,你需要掌握:1.建立邻接矩阵,2.Prim算法。建立邻接矩阵 上述带权无向图对应的二维数组,根据它建立邻接矩阵,如图1建立下列邻接矩阵。注意:INF表示无穷大,表示整数:32767 intA[MAXV][MAXV];Prim算法 普里姆(Prim)算法是一种构造性算法,从候选边中挑
40 10
|
23天前
|
存储 算法 C++
【C++数据结构——图】图的邻接矩阵和邻接表的存储(头歌实践教学平台习题)【合集】
本任务要求编写程序实现图的邻接矩阵和邻接表的存储。需掌握带权有向图、图的邻接矩阵及邻接表的概念。邻接矩阵用于表示顶点间的连接关系,邻接表则通过链表结构存储图信息。测试输入为图的顶点数、边数及邻接矩阵,预期输出为Prim算法求解结果。通关代码提供了完整的C++实现,包括输入、构建和打印邻接矩阵与邻接表的功能。
44 10
|
23天前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
33 7

热门文章

最新文章