竞赛题库java1

排队

问题

Makik在上次的比赛后沉迷原神。现在要向你展示他给史莱姆排队的能力。
具体而言。我们用一个大写字母来表示一种史莱姆,
同种史莱姆之间没有区别,这里我们认为共有26种不同类型的史莱姆。
Makik有一个已经排好队的史莱姆序列E,
现在又给了你一个还没排好队的史莱姆序列A,
请问最少多少次操作能巴A排成B呢?这个问题太简单了,
所以 Makik,加了个限制条件:
每次移动A中的史莱姆的时候,
只能将恕要移动的史莱姆从原来的位置移动到队头,
也就是第一个史莱姆的前面。请问在这个限制下,
最少多少次操作可以将A排成B呢?

输入

10

SIAJOIWUGB

IBUSJGWAOI

输出

7

思路

在此代码中,我们使用一个二维数组dp来存储中间结果。
dp[i][j]表示将字符串A的前i+1个字符排列成字符串B的前j+1个字符
所需的最少操作次数。
我们使用两个嵌套循环来计算所有可能的子字符串长度和起始位置。

在每个子字符串中,如果首尾字符相同,则不需要进行任何操作,
因此dp[i][j]的值与dp[i+1][j-1]相同。如果首尾字符不同,
则我们需要将其中一个字符移到队头,这需要至少一次操作。
我们可以通过比较将第一个字符移到队头和将第二个字符
移到队头所需的操作次数来选择最佳操作。
最终结果存储在dp[0][n-1]中,其中n是字符串A的长度。

棋盘

棋盘

题解

题解C++

java版

package com.liujiabao.algorithm1;

import java.util.Arrays;
import java.util.Scanner;

public class Main {

    public int M;

    public int MAX_VA=Integer.MAX_VALUE;
    public int[][] dp,dist;

    public int[] distx=new int[]{-1,0,1,0},disty=new int[]{0,1,0,-1};

    public Main(int M){
        dp=new int[M+1][M+1];
        dist=new int[M+1][M+1];
        this.M=M;
        for (int i=0;i<dist.length;i++){
            Arrays.fill(dist[i],MAX_VA);
            Arrays.fill(dp[i],-1);
        }

    }

    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        int m,n;
        int x,y,value;
        m=scanner.nextInt();
        n=scanner.nextInt();
        Main java22=new Main(m);
        while ((n--)>0){
            x=scanner.nextInt();
            y=scanner.nextInt();
            value=scanner.nextInt();
            java22.setDP(x,y,value);
        }
        scanner.close();
        java22.dfs(1,1,0,0);
        if(java22.dist[m][m]== java22.MAX_VA){
            System.out.println(-1);
        }else {
            System.out.println(java22.dist[m][m]);
        }
    }



    public void setDP(int x,int y,int value){
        dp[x][y]=value;
    }

    /*
    * 几种情况
    * 1.当超出棋盘时,不能转移,做可行性剪枝
    * 2.当(nx,ny)无色时,再分两类
    *   2.1 如果在(x,y)已经用过魔法,那么由于不能练习使用,不可转移
    *   2.2 如果在(x,y)点没有用过魔法,那么可以使用魔法染色,花费2.
    * 3.当(nx,ny)与(x,y)不同色时:转移,花费1
    * 4.同色:花费0
    * 但走到某个点的花费已经比目前最优解贵了,就不搜了
    *
    * */
    public void dfs(int x,int y,int cost,int used){
        if(dist[x][y]<=cost) return;

        dist[x][y]=cost;

        if(x==M&&y==M) return;

        for(int i=0;i<4;i++){
            int nx=x+distx[i],ny=y+disty[i];
            if(nx<1||nx>M||ny<1||ny>M) continue;
            if(dp[nx][ny]==-1){
                if(used==1) continue;
                else {
                    dp[nx][ny]=dp[x][y];
                    dfs(nx,ny,cost+2,1);
                    dp[nx][ny]=-1;
                }
            }
            else if(dp[nx][ny] == dp[x][y]) dfs(nx,ny,cost,0);
            else dfs(nx,ny,cost+1,0);
        }
    }
}

简单瞎搞题目(动态规划,bitset)

题目

思路
一衍一
想了一天大致明白了,以上两位的思路有助于理解,上java代码(运行超时)。

package com.liujiabao.algorithm1;

import java.io.IOException;
import java.util.BitSet;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) throws IOException {
        Scanner scanner=new Scanner(System.in);
        int n=scanner.nextInt();
        int NL=101*101*101;
        BitSet bitSet=new BitSet(NL);
        for(int j=0;j<1;j++){
            int l=scanner.nextInt();
            int r=scanner.nextInt();
            for(int i=l;i<=r;i++){
                bitSet.set(i*i);
            }
        }
        for(int j=1;j<n;j++){
            int l=scanner.nextInt();
            int r=scanner.nextInt();
            BitSet bitSet1=new BitSet(NL);
            for(int i=l;i<=r;i++){
                bitSet1.or(shiftLeft(bitSet,i*i));
            }
            bitSet=bitSet1;
        }
        System.out.println(bitSet.cardinality());
    }


    private static BitSet shiftLeft(BitSet bitset, int n) {
        BitSet result = new BitSet(bitset.size() + n);
        for (int i = 0; i < bitset.size(); i++) {
            result.set((i + n) % bitset.size(), bitset.get(i));
        }
        return result;
    }
}


戳气球

题目
思路

总结

区间dp


import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
//      dp[i][j] = math.max ( dp[i][j], dp[i][k]+dp[k][j] + dp[i][k]*dp[k][k]*dp[k][j])
        Scanner scanner=new Scanner(System.in);
        int N=scanner.nextInt();
        int[] nums=new int[N+2];
        int[][] dp=new int[N+2][N+2];
        for(int i=0;i<N+2;i++){
            if(i==0||i==N+1){
                nums[i]=1;
            }else {
                nums[i]=scanner.nextInt();
            }
        }

        for(int i=N-1;i>=0;i--){
            for(int j=i+2;j<=N+1;j++){
                for(int k=i+1;k<j;k++) {
                    dp[i][j] = Math.max(dp[i][j], dp[i][k] + dp[k][j] + nums[i] * nums[k] * nums[j]);
                }
            }
        }

        System.out.println(dp[0][N+1]);
        scanner.close();
    }
}

//4
//        3 1 5 8
//
//167

树上自连

链接

链接

两数相加

力扣两数相加

题解java

解题时多想

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        return add(false, l1, l2);
    }
    /**
     * @param carry 是否进位
     * @param l1 节点
     * @param l2 节点
     * @return
     */
    public ListNode add(boolean carry, ListNode l1, ListNode l2) {
        if (l1 == null && l2 == null && !carry) return null;
        int a = l1 == null ? 0 : l1.val;
        int b = l2 == null ? 0 : l2.val;
        int sum = carry ? a + b + 1 : a + b;
        return new ListNode(sum % 10 ,add(sum >= 10, l1 == null ? null: l1.next, l2 == null ? null : l2.next));
    }
}

无重复字符的最长子串

i=-1;用的很巧妙
无重复最长子串

最长回文串

最长回文串

java代码实现

package com.liujiabao.algorithm2;


import java.util.ArrayList;
import java.util.Stack;

class Solution {
    public static void main(String[] args) {
        String s="a";
        Solution solution=new Solution();
        System.out.println(solution.longestPalindrome(s));
    }

    public String longestPalindrome(String s) {
        int n=s.length();
        boolean[][] dp=new boolean[n][n];
        int maxLen=0;
        int start=0;

        /*
         * 单个字符是回文串
         * dp[i][j] 代表第 i个到第j个字符是回文串
        * 从 len长度为 1 , 2 ,3,4....n依次往上判断是否为回文串
        * 回文串长度有两种情况,一种是偶数,一种是奇数
        * 所有先解决以上问题初始化:对每一个字符设置为true,对每一个字符相邻的字符比较看他们是否可以是回文串
        *
        * */
        for(int i=0;i<n;i++){
            dp[i][i] =true;
            if(i<n-1&&s.charAt(i)==s.charAt(i+1)){
                dp[i][i+1]=true;
                maxLen=2;
                start=i;
            }
        }

        /*
        * 开始从len:3,4,5,6,...n(因为一开始初始化已经解决了len:1,2)长度判定
        * */
        for(int len=3;len<=n;len++){
            /*
            * 既然你的len是从小往上,递增的
            * 所有之前的不需要再比较了,所有i只需要比较到 i<n-len+1
            * */
            for(int i=0;i<n-len+1;i++){
                int j=i+len-1;
                if(s.charAt(i)==s.charAt(j)&&dp[i+1][j-1]){
                    dp[i][j]=true;
                    if(len>maxLen){
                        maxLen=len;
                        start=i;
                    }
                }
            }
        }

        // substring 切割的是 [i,i+len) ,右边是开区间
        if(maxLen==0){
            return s.substring(start,start+1);
        }
        return s.substring(start,start+maxLen);
    }
}

盛最多水的容器

盛多少的容器

public class Solution {
    public int maxArea(int[] height) {
        int l = 0, r = height.length - 1;
        int ans = 0;
        while (l < r) {
            int area = Math.min(height[l], height[r]) * (r - l);
            ans = Math.max(ans, area);
            if (height[l] <= height[r]) {
                ++l;
            }
            else {
                --r;
            }
        }
        return ans;
    }
}

三数之和

三数之和

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        int n = nums.length;
        Arrays.sort(nums);
        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        // 枚举 a
        for (int first = 0; first < n; ++first) {
            // 需要和上一次枚举的数不相同
            if (first > 0 && nums[first] == nums[first - 1]) {
                continue;
            }
            // c 对应的指针初始指向数组的最右端
            int third = n - 1;
            int target = -nums[first];
            // 枚举 b
            for (int second = first + 1; second < n; ++second) {
                // 需要和上一次枚举的数不相同
                if (second > first + 1 && nums[second] == nums[second - 1]) {
                    continue;
                }
                // 需要保证 b 的指针在 c 的指针的左侧
                while (second < third && nums[second] + nums[third] > target) {
                    --third;
                }
                // 如果指针重合,随着 b 后续的增加
                // 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
                if (second == third) {
                    break;
                }
                if (nums[second] + nums[third] == target) {
                    List<Integer> list = new ArrayList<Integer>();
                    list.add(nums[first]);
                    list.add(nums[second]);
                    list.add(nums[third]);
                    ans.add(list);
                }
            }
        }
        return ans;
    }
}

接近三数之和

接近三数之和

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int n = nums.length;
        int best = 10000000;

        // 枚举 a
        for (int i = 0; i < n; ++i) {
            // 保证和上一次枚举的元素不相等
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            // 使用双指针枚举 b 和 c
            int j = i + 1, k = n - 1;
            while (j < k) {
                int sum = nums[i] + nums[j] + nums[k];
                // 如果和为 target 直接返回答案
                if (sum == target) {
                    return target;
                }
                // 根据差值的绝对值来更新答案
                if (Math.abs(sum - target) < Math.abs(best - target)) {
                    best = sum;
                }
                if (sum > target) {
                    // 如果和大于 target,移动 c 对应的指针
                    int k0 = k - 1;
                    // 移动到下一个不相等的元素
                    while (j < k0 && nums[k0] == nums[k]) {
                        --k0;
                    }
                    k = k0;
                } else {
                    // 如果和小于 target,移动 b 对应的指针
                    int j0 = j + 1;
                    // 移动到下一个不相等的元素
                    while (j0 < k && nums[j0] == nums[j]) {
                        ++j0;
                    }
                    j = j0;
                }
            }
        }
        return best;
    }
}

优美的排列

优美的排列

class Solution {
    List<Integer>[] match;
    boolean[] vis;
    int num;

    public int countArrangement(int n) {
        vis = new boolean[n + 1];
        match = new List[n + 1];
        for (int i = 0; i <= n; i++) {
            match[i] = new ArrayList<Integer>();
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                if (i % j == 0 || j % i == 0) {
                    match[i].add(j);
                }
            }
        }
        backtrack(1, n);
        return num;
    }

    public void backtrack(int index, int n) {
        if (index == n + 1) {
            num++;
            return;
        }
        for (int x : match[index]) {
            if (!vis[x]) {
                vis[x] = true;
                backtrack(index + 1, n);
                vis[x] = false;
            }
        }
    }
}

判断通过操作能否让字符串相等 II

判断通过操作能否让字符串相等 II

训练师最大匹配

训练师最大匹配

内存超出

import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Stack;

public class Solution {
    public static void main(String[] args) {
        int[] players=new int[]{1,1000};
        int[] trainers=new int[]{1000,1};
        Solution solution=new Solution();
        System.out.println(solution.matchPlayersAndTrainers(players,trainers));
        // 2
    }

    public int matchPlayersAndTrainers(int[] players, int[] trainers) {
        // 长度
        int leni=players.length;
        int lenj=trainers.length;
        // 图  i行代表第i名运动员,j列代表第j个训练师
        int[][] grap=new int[leni+1][lenj+1];

        // 保留第j名训练师训练的第i名运动员
        int[] visitedi=new int[leni+1];
        int[] visitedj=new int[lenj+1];

        // 最大匹配数
        int num=0;


        // 循环匹配
        for(int i=1;i<=leni;i++){
            if(visitedi[i]>0){
                continue;
            }
            for(int j=1;j<=lenj;j++){
                if(players[i-1]<=trainers[j-1]){
                    if(visitedj[j]==0){
                        visitedi[i]=j;
                        visitedj[j]=i;
                        num++;
                        break;
                    }else if(players[i-1]>players[visitedj[j]-1]){
                        int temp=visitedj[j];
                        visitedi[visitedj[j]]=0;
                        visitedj[j]=i;
                        visitedi[i]=j;
                        i=temp-1;
                        break;
                    }
                }
            }
        }

        return num;
    }

}
/*
* 通过二部图
* 匹配:
* 第i名运动员小于等于第j名训练师的能力值进行匹配,如果第k名运动员已经匹配了第j名训练师,判断i和k谁的能力值大小,大的匹配,小的进入未匹配状态
*
*
*
* */

双指针+贪心

class Solution {
    public int matchPlayersAndTrainers(int[] players, int[] trainers) {
        Arrays.sort(players);
        Arrays.sort(trainers);
        int m = players.length, n = trainers.length;
        int count = 0;
        for (int i = 0, j = 0; i < m && j < n; i++, j++) {
            while (j < n && players[i] > trainers[j]) {
                j++;
            }
            if (j < n) {
                count++;
            }
        }
        return count;
    }
}


最小平均差

最小平均差

前缀和
用long保存
Java中的long是一种基本数据类型,它占用64位(8字节)的内存空间。long类型的范围从-9223372036854775808到9223372036854775807。在大多数情况下,int类型就足够用了,因为它的范围从-2147483648到2147483647,对于大多数应用来说已经足够了。然而,如果你需要处理非常大的数字,或者想要确保你的代码在所有情况下都能正常工作(例如,处理的数据可能大于int的最大值),那么使用long类型就很有必要。

class Solution {
  public int minimumAverageDifference(int[] nums) {
    int n = nums.length, res = 0;
    long min = Integer.MAX_VALUE;
    long[] sum = new long[n + 1];
    for (int i = 0; i < n; i++) {
      sum[i + 1] = sum[i] + nums[i];
    }
    for (int i = 0; i < n; i++) {
      long diff = Math.abs(sum[i + 1] / (i + 1) - ((n - i - 1 == 0) ? 0 : (sum[n] - sum[i + 1]) / (n - i - 1)));
      if (diff < min) {
        res = i;
        min = diff;
      }
    }
    return res;
  }
}

    public int minimumAverageDifference(int[] nums) {
        // 长度
        int len=nums.length;
        // 前缀和
        long[] prefix_and = new long[len];
        // 初始化
        for(int i=0;i<len;i++){
            prefix_and[i]=nums[i];
            if(i>0){
                prefix_and[i]+=prefix_and[i-1];
            }
        }
        // 计算
        long min=Integer.MAX_VALUE;
        int index=-1;
        long max=prefix_and[len-1];
        for(int i=0;i<len;i++){
            //
            long temp;
            if(len-i-1==0){
                temp=Math.abs((prefix_and[i]/(i+1))-0);
            }else {
                temp=Math.abs((prefix_and[i]/(i+1))-((max-prefix_and[i])/(len-i-1)));
            }
            if(temp<min){
                min=temp;
                index=i;
            }
        }



        return index;
    }

周末

周末

换楼请求

换楼请求

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值