算法题目整合2

128. 小美的排列询问

题目描述

小美拿到了一个排列。她想知道在这个排列中,x 和 y 是否是相邻的。你能帮帮她吗?排列是指一个长度为 n 的数组,其中 1 到 n 每个元素恰好出现一次。

输入描述

第一行输入一个正整数 n(1 <= n <= 200000),代表排列的长度。 
第二行输入 n 个正整数 ai,代表排列的元素。 
第三行输入两个正整数 x 和 y(1 <= ai, x, y <= n),用空格隔开。
保证 x != y

输出描述

如果 x 和 y 是相邻的,输出 Yes;否则输出 No。

输入示例

4
1 4 2 3
2 4

输出示例

Yes

提示信息

输入的排列是 1 4 2 3,x = 2,y = 4,2 和 4 是相邻的。输出 Yes.
import java.util.*;
class Main{
    public static void main (String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        Map<Integer, Integer> map = new HashMap<>();
        for(int i = 0; i < n; i++){
            map.put(sc.nextInt(), i);
        }
        int num1 = sc.nextInt();
        int num2 = sc.nextInt();
        int index1 = map.get(num1);
        int index2 = map.get(num2);
        if(index2 - index1 == 1 || index1 - index2 == 1){
            System.out.println("Yes");
        }else{
            System.out.println("No");
        }
    }
}

129. 小美走公路

题目描述

有一个环形的公路,上面共有 n 站,现在给定了顺时针第 i 站到第 i + 1 站之间的距离(特殊的,也给出了第 n 站到第 1 站的距离)。小美想沿着公路第 x 站走到第 y 站,她想知道最短的距离是多少?

输入描述

第一行输入一个正整数 n(1 <= n <= 10^5),代表站的数量。 
第二行输入 n 个正整数 ai(1 <= ai <= 10^9),前 n - 1 个数代表顺时针沿着公路走,i 站到第 i + 1 站之间的距离;
最后一个正整数代表顺时针沿着公路走,第 n 站到第 1 站的距离。
 第三行输入两个正整数 x 和 y(1 <= x, y <= n),代表小美的出发地和目的地。

输出描述

一个正整数,代表小美走的最短距离。

输入示例

3
1 2 2
2 3

输出示例

2

构建一个环形链表,距离需要用long来定义。

import java.util.*;
class Main{
   public static void main (String[] args) {
       Scanner sc = new Scanner(System.in);
       int[] nums = new int[]{63, 21, 84, 54, 94, 74, 51, 65};
       int sum = 0;
       for(int i = 0; i < nums.length; i++){
           sum += nums[i];
       }
       int n = sc.nextInt();
       ListNode head = new ListNode();
       ListNode tail = head;
       long distance = 0;
       for(int i = 0; i < n; i++){
           int num = sc.nextInt();
           ListNode node = new ListNode(num);
           tail.next = node;
           tail = node;
           distance += num;
       }
       tail.next = head.next;
       tail = tail.next;
       int left = sc.nextInt(), right = sc.nextInt();
       long cur = 0;
       if (left < right){
           for(int i = 1; i < left; i++){
               tail = tail.next;
           }
           for(int i = left; i < right; i++){
               cur += tail.val;
               tail = tail.next;
           }
       }else{
           for(int i = 1; i < right; i++){
               tail = tail.next;
           }
           for(int i = right; i < left; i++){
               cur += tail.val;
               tail = tail.next;
           }
       }
       System.out.println(Math.min(cur, distance - cur));
   }
}
class ListNode{
   int val;
   ListNode next;
   ListNode(){}
   ListNode(int val){
       this.val = val;
   }
}

130. 小美的蛋糕切割

题目描述

小美有一个矩形的蛋糕,共分成了 n 行 m 列,共 n * m 个区域,每个区域是一个小正方形,已知蛋糕每个区域都有一个美味度。
她想切一刀把蛋糕切成两部分,自己吃一部分,小团吃另一部分。 
小美希望两个人吃的部分的美味度之和尽可能接近,请你输出|s1 - s2|的最小值。(其中 s1 代表小美吃的美味度,s2 代表小团吃的美味度)。 
请务必保证,切下来的区域都是完整的,即不能把某个小正方形切成两个小区域。

输入描述

第一行输出两个正整数 n 和 m(1 <= n, m <= 10^3),代表蛋糕区域的行数和列数。
接下来的 n 行,每行输入 m 个正整数 aij(1 <= aij <= 10^4),用来表示每个区域的美味度。

输出描述

一个整数,代表|s1-s2|的最小值。

输入示例

2 3
1 1 4
5 1 4

输出示例

0

提示信息

把蛋糕像这样切开:
1 1 | 4 
5 1 | 4 
左边蛋糕美味度之和是 8 右边蛋糕美味度之和是 8 所以答案是 0。
import java.util.*;
class Main{
    public static void main (String[] args) {
        Scanner sc = new Scanner(System.in);
        int m = sc.nextInt();
        int n = sc.nextInt();
        int sum = 0;
        int[][] cake = new int[m][n];
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                cake[i][j] = sc.nextInt();
                sum += cake[i][j];
            }
        }
        int res = sum;
        int pre = 0;
        //横切
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                pre += cake[i][j];
            }
            res = Math.min(res, Math.abs(pre - (sum - pre)));
        }
        pre = 0;
        //竖切
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                pre += cake[j][i];   
            }
            res = Math.min(res, Math.abs(pre - (sum - pre)));
        }
        System.out.println(res);
    }
}

131. 小美的字符串变换

题目描述

小美拿到了一个长度为 n 的字符串,她希望将字符串从左到右平铺成一个矩阵
(先平铺第一行,然后是第二行,以此类推,矩阵有 x 行 y 列,必须保证 x * y=n,即每 y 个字符换行,共 x 行)。 
该矩阵的权值定义为这个矩阵的连通块数量。小美希望最终矩阵的权值尽可能小,你能帮小美求出这个最小权值吗? 
注:我们定义,上下左右四个方向相邻的相同字符是连通的。

输入描述

第一行输入一个正整数 n(1 <= n <= 10^4),代表字符串的长度。 
第二行输入一个长度为 n 的、仅由小写字母组成的字符串。

输出描述

输出一个整数表示最小权值。

输入示例

9
aababbabb

输出示例

2

提示信息

平铺为 3 * 3 的矩阵:
aab
abb
abb
共有 2 个连通块,4 个 a 和 5 个 b。

利用dfs进行求解,本质上就是求岛屿数量问题leetcode200,只不过需要自己进行建图处理。

import java.util.*;
class Main{
    public static void main (String[] args) {
        Scanner sc = new Scanner(System.in);
        int len = sc.nextInt();
        String s = sc.next();
        char[] ch1 = s.toCharArray();
        int res = Integer.MAX_VALUE;
        for(int i = 1; i * i <= len; i++){
            if(len % i != 0)  continue;
            int m = i;
            int n = len / i;
            char[][] ch = new char[m][n];
            int index = 0;
            for(int x = 0; x < m; x++){
                for(int y = 0; y < n; y++){
                    ch[x][y] = ch1[index];
                    index++;
                }
            }
            int cnt = 0;
            for(int x = 0; x < m; x++){
                for(int y = 0; y < n; y++){
                    if(ch[x][y] != '0'){
                        char flag = ch[x][y];
                        dfs(ch, x, y, m, n, flag);
                        cnt++;
                    }
                }
            }
            res = Math.min(res, cnt);
            ch = new char[n][m];
            index = 0;
            for(int x = 0; x < n; x++){
                for(int y = 0; y < m; y++){
                    ch[x][y] = ch1[index];
                    index++;
                }
            }
            cnt = 0;
            for(int x = 0; x < n; x++){
                for(int y = 0; y < m; y++){
                    if(ch[x][y] != '0'){
                        char flag = ch[x][y];
                        dfs(ch, x, y, n, m, flag);
                        cnt++;
                    }
                }
            }
            res = Math.min(res, cnt);
        }
        System.out.println(res);
    }
    public static void dfs(char[][] ch, int x, int y, int m, int n, char flag){
        if(!inArea(x, y, m, n) || ch[x][y] != flag)  return;
        ch[x][y] = '0';
        dfs(ch,x-1,y,m,n,flag);
        dfs(ch,x+1,y,m,n,flag);
        dfs(ch,x,y-1,m,n,flag);
        dfs(ch,x,y+1,m,n,flag);
    }
    public static boolean inArea(int x, int y, int m, int n){
        if(x < 0 || y < 0 || x >= m || y >= n)  return false;
        return true;
    }
}

132. 小美的树上染色

题目描述

小美拿到了一棵树,每个节点有一个权值。初始每个节点都是白色。 
小美有若干次操作,每次操作可以选择两个相邻的节点,如果它们都是白色且权值的乘积是完全平方数,小美就可以把这两个节点同时染红。 
小美想知道,自己最多可以染红多少个节点?

输入描述

第一行输入一个正整数 n(1 <= n <= 10^5),代表节点的数量。
第二行输入 n 个正整数 ai(1 <= ai <= 10^9),代表每个节点的权值。
接下来的 n - 1 行,每行输入两个正整数 u,v(1 <= u, v <= n),代表节点 u 和节点 v 有一条边连接。

输出描述

输出一个整数,表示最多可以染红的节点数量。

输入示例

3
3 3 12
1 2
2 3

输出示例

2

提示信息

可以染红第二个和第三个节点。 
请注意,此时不能再染红第一个和第二个节点,因为第二个节点已经被染红。 因此,最多染红 2 个节点。

dfs+List记录相邻节点

import java.util.*;
class Main{
    static long[] weights;
    static List<List<Integer>> neiborhoods;
    static boolean[] isRed;
    static int res = 0;
    public static void main (String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        weights = new long[n + 1];
        isRed = new boolean[n + 1];
        for(int i = 1; i <= n; i++){
            weights[i] = sc.nextInt();
        }
        neiborhoods = new ArrayList<>(n + 1);
        for(int i = 0; i <= n; i++){
            neiborhoods.add(new ArrayList<>());
        }
        for(int i = 1; i < n; i++){
            int u = sc.nextInt();
            int v = sc.nextInt();
            neiborhoods.get(u).add(v);
            neiborhoods.get(v).add(u);
        }
        dfs(1, -1);
        System.out.println(res);
    }
    public static void dfs(int current, int last){
        for(int neiborhood : neiborhoods.get(current)){
            if(neiborhood == last)  continue;
            dfs(neiborhood, current);
            if(!isRed[current] && !isRed[neiborhood] && redValid(current, neiborhood)){
                isRed[current] = true;
                isRed[neiborhood] = true;
                res += 2;
            }
        }
    }
    public static boolean redValid(int current, int neiborhood){
        long Mutiple = weights[current] * weights[neiborhood];
        long square = (long) Math.sqrt(Mutiple);
        return square * square == Mutiple;
    }
}
  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值