算法练习- 其他算法练习

航天器

以一个数组中的任意两个元素计算面积,索引差值为宽度w,两值之间的最小值为高度h,面积s = w*h。求数组元素可以组成的最大面积。

示例一
输入
10,9,8,7,6,5,4,3,2,1
输出
25

说明:
10米高支柱和5米高支柱之间宽度为5,
高度取小值也是5,面积为25
任取其他两根支柱所能获得的面积都小于25 所以最大面积为25

思路:
依次取每一个元素,与其他元素计算面积,取最大面积。
python代码:

在这里插入代码片

java代码

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

public class Main013 {
    
     // 公有类名 必须与类文件名相同
    public static void main(String[] args) {
    
    

        // 异常捕获
        try {
    
    
            // 输入
            Scanner scanner = new Scanner(System.in);
            String line = scanner.nextLine();

            solution(line);
        } catch(Exception e){
    
    
            System.out.println(e.getMessage());
        }

    }

    // 私有方法-供类内部 调用
    private static void solution(String line) {
    
    
        // 字符串分割  10,9,8,7,6,5,4,3,2,1
        String[] split = line.trim().split(",");
        // Arrays.stream 返回元素序列  映射为Long
        long[] longs = Arrays.stream(split)
                .mapToLong(Long::parseLong)
                .toArray();

        long res = 0;
        for (int i = 0; i < split.length; i++) {
    
    
            for (int j = i + 1; j < split.length; j++) {
    
    
                // Math 数学计算
                long area = Math.min(longs[i], longs[j]) * (j - i);
                res = Math.max(res, area);
            }
        }

        System.out.println(res);
    }
}

分糖果

输入num个糖果,每次取出一半分给同学们,当糖果不能平均分配(/2)时
可以从糖果盒中取出一个或放回一个糖果。
至少需要多少次能将手中糖果分至只剩一颗?
取出、放回算作一次;
平均分配算作一次;

示例一
输入
15
输出
5
说明
15+1=16
16/2=8
8/2=4
4/2=2
2/2=1

思路:

  • 至少多少次;
  • 不够平均分配时,应该++ 还是-- ?标准?
  • ( n u m + 1 ) / 2 % 2 = = 0 {(num+1) / 2 \% 2} == 0 (num+1)/2%2==0 时则++,否则–
    python代码
在这里插入代码片

java代码

import java.util.Scanner;


public class Main048 {
    
    
    public static void main(String[] args){
    
    

        try{
    
    
            Scanner scanner = new Scanner(System.in);
            String num_str = scanner.nextLine();
            long num = Integer.parseInt(num_str);

            solution(num);
        }catch (Exception e){
    
    
            System.out.println(e.getMessage());
        }


    }

    private static void solution(long num){
    
    
        long times = 0;

        while(num != 1){
    
    
            if(num == 3){
    
     // -1  /2   特殊处理
                times += 2; // 至少
                break;
            }

            if(num % 2 != 0 ){
    
     // 无法平均分配时 该 ++ 还是该 -- ?
                if((num + 1) / 2 % 2 == 0){
    
    
                    num ++; // 取
                }else{
    
    
                    num --; // 放
                }
                times ++; // 取糖果 或者 放回糖果  算作一次
            }

            num = num / 2; // 平均分配   算作一次
            times ++;
        }

        System.out.println(times);
    }
}

卡片组成的最大数字

输入描述
正整数字符串
输出描述
最大数字字符串

示例一
输入
22,221
输出
22221

示例二
输入
4589,101,41425,9999
输出
9999458941425101

思路:

  • 比较两个元素的大小;
  • 拼接在前面,形成的数值大,则认为该元素
  • 对所有数值字符串降序排序;最后拼接。
    python实现:

def comp_two_str(s1, s2):
    """ 比较两个数字串的拼接 """
    s1_ = s1 + s2
    s2_ = s2 + s1
    return s1_ > s2_

# 冒泡排序
def bubble_sort(alist):
    n = len(alist)
    if n < 2:
        return alist
    for i in range(n-1):
        for j in range(i+1, n):
            if comp_two_str(alist[i], alist[j]):
                continue
            else:
                alist[i], alist[j] = alist[j], alist[i]

    return alist


if __name__ == '__main__':
    alist = input().strip().split(",")
    bubble_sort(alist)
    print("".join(alist))

 
java实现

  • 有点问题
  • 22,2221
  • 2221,22
import java.util.Arrays;
import java.util.Scanner;


public class Main079 {
    
    
    public static void main(String[] args) {
    
    
        try (Scanner scanner = new Scanner(System.in)) {
    
    
            String nums = scanner.nextLine();
            solution(nums);
        }
    }

    private static void solution(String nums) {
    
    
        StringBuilder builder = new StringBuilder();

        Arrays.stream(nums.split(","))
                .sorted((s1, s2) -> {
    
    
                    char[] v1 = s1.toCharArray();
                    char[] v2 = s2.toCharArray();
                    int len1 = v1.length;
                    int len2 = v2.length;

                    if (len1 == len2) {
    
    
                        return s2.compareTo(s1);
                    }

                    int min = Math.min(len1, len2);
                    for (int i = 0; i < min; i++) {
    
    
                        char c1 = v1[i];
                        char c2 = v2[i];
                        if (c1 != c2) {
    
    
                            return c2 - c1;
                        }
                    }

                    if (len1 > len2) {
    
    
                        return v1[0] - v1[min];
                    } else {
    
    
                        return v2[min] - v2[0];
                    }
                })
                .forEach(builder::append);

        System.out.print(builder);
    }
}

分苹果

A 按照二进制规则加和,按位加且不进位; 分左右两份。
B 按照正常十进制加和,分左右两份。
在满足A 等分 两份时,B 划分的两份中的最大值?

第一行输入苹果数,
第二行输入每个苹果的重量

示例一
输入
3
3 5 6
输出
11

示例二
输入
8
7258 6579 2602 6716 3050 3564 5396 1773
输出
35165

思路:

  • 苹果重量排序;
  • 从第二个苹果开始,划分左边一份,右边一份;
  • 左边分别按照AB的方法求和;
  • 右边同样按照AB的方法求和;
  • 当按照A方法求和 两边相等时,取B 方法两份各自求和的最大值。

python实现

def get_b_max(m, alist):
    b_max = -1
    for i in range(1, m):
        # 分成左右两份后,分别按照A B规则 对两边求和
        a_left_sum = 0
        a_right_sum = 0
        b_left_sum = 0
        b_right_sum = 0
        # left 求和
        for j in range(i):
            # 左边 按照A规则求和
            a_left_sum ^= alist[j]
            # 左边按照B 规则求和
            b_left_sum += alist[j]

        # right 求和
        for j in range(i, m):
            a_right_sum ^= alist[j]
            b_right_sum += alist[j]

        # 满足A 均等分时
        if a_left_sum == a_right_sum:
            cur_max = max(b_left_sum, b_right_sum)
            b_max = max(cur_max, b_max)

    return b_max


if __name__ == '__main__':
    m = int(input().strip())
    alist = list(map(int, input().strip().split()))
    alist.sort()
    # 计算B获取的最大重量
    result = get_b_max(m, alist)
    print(result)

java实现

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

public class Main086 {
    
    
    public static void main(String[] args) {
    
    

        try {
    
    
            Scanner scanner = new Scanner(System.in);
            int m = Integer.parseInt(scanner.nextLine());
            String weightString = scanner.nextLine();

            solution(weightString);
        }catch(Exception e){
    
    
            System.out.println(e.getMessage());
        }
    }

    private static void solution(String line) {
    
    
        String[] strs = line.split(" ");
        int[] ints = new int[strs.length];
        // 转为整型
        for (int i = 0; i < strs.length; i++) {
    
    
            ints[i] = Integer.parseInt(strs[i]);
        }

        // 排序数组本身
        Arrays.sort(ints);
        // B最大重量
        int max = -1;
        for (int i = 1; i < ints.length - 1; i++) {
    
    
            int sumBin1 = 0;
            int sumBin2 = 0;
            int sum1 = 0;
            int sum2 = 0;
            //left
            for (int j = 0; j < i; j++) {
    
    
                sumBin1 = sumBin1 ^ ints[j];
                sum1 += ints[j];
            }
            //right
            for (int j = i; j < ints.length; j++) {
    
    
                sumBin2 = sumBin2 ^ ints[j];
                sum2 += ints[j];
            }

            if (sumBin1 == sumBin2) {
    
     // 满足A 均分两份
                max = Math.max(Math.max(sum1, sum2), max);
            }
        }

        System.out.println(max);
    }
}

敏感字段加密

  • 给定一个由多个命令字组成的命令字符串;

  • 字符串长度小于等于127字节,只包含大小写字母,数字,下划线和偶数个双引号,命令字之间以一个或多个下划线_进行分割

  • 可以通过两个双引号""来标识包含下划线_的命令字或空命令字(仅包含两个双引号),双引号不会在命令字内部出现

  • 对指定索引的敏感字段进行加密,替换为******(6个*),并删除命令字前后多余的下划线_。
    如果无法找到指定索引的命令字,输出字符串ERROR

输入描述
第一行为命令字索引 idx
第二行为命令字符串 cmd_string

输出描述
输出处理后的命令字符串
如果无法找到指定索引的命令字,输出字符串ERROR

示例一
输入
1
password__a12345678_timeout_100
输出
password_******_timeout_100

示例二
输入
2
aaa_password_“a12_45678”_timeout__100_“”_
输出
aaa_password_“******”_timeout_100_“”

思路:

  • 以_分割字符串;
  • 预处理结果列表并存入temp[ ],空字符直接删,空命令直接存起来,以单个双引号开头的要拼接,直到以单个双引号结束的命令,然后存起来;
  • 一般的命令字符串直接存起来;
  • 判断idx索引是否有效 0-n,有效则temp对应索引处的值用*替换(注意命令双引号时要保留双引号)
  • 索引无效,输出ERROR字符串

python代码

def preprocess_list(alist):
    temp = []
    flag = False
    partial_cmd = ""
    for i in alist:
        if not i:
            continue
        elif i == '""':
            temp.append(i)
        elif i.startswith('"'):
            flag = True
            partial_cmd += i
        elif i.endswith('"'):
            flag = False
            partial_cmd += i
            temp.append(partial_cmd)
            partial_cmd = ""
        elif i:
            if flag:
                partial_cmd += i
            else:
                temp.append(i)

    return temp


if __name__ == '__main__':
    idx = int(input().strip())
    cmd_string = input().strip()

    cmd_list = cmd_string.split("_")
    # ['password', '', 'a12345678', 'timeout', '100']
    # ['aaa', 'password', '"a12', '45678"', 'timeout', '', '100', '""', '']
    print("current list:", cmd_list)

    cmd_list = preprocess_list(cmd_list)
    print("processed list:", cmd_list)

    # 指定索引处的 命令是否存在
    if idx >= 0 and idx < len(cmd_list):
        cur_cmd = cmd_list[idx]
        if cur_cmd.startswith('"') and cur_cmd.endswith('"'):
            cmd_list[idx] = '"' + '*'*6 + '"'
        else:
            cmd_list[idx] = '*'*6
        print("_".join(cmd_list))
    else:
        print("ERROR")

java实现

import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;


public class Main082 {
    
    
    public static void main(String[] args) {
    
    
        try (Scanner scanner = new Scanner(System.in)) {
    
    
            int K = Integer.parseInt(scanner.nextLine());
            String S = scanner.nextLine();
            String res = solution(K, S);
            System.out.println(res);
        }
    }

    private static String solution(int k, String s) {
    
    
        List<String> commands = new LinkedList<>();


        char[] chars = s.toCharArray();
        for (int i = 0; i < s.length(); i++) {
    
    
            char cur = chars[i];
            String command = "";
            if (cur == '"') {
    
    
                int rPosQ = s.indexOf('"', i + 1);
                command = s.substring(i, rPosQ + 1);
                i = rPosQ + 1;
            } else {
    
    
                int pos_ = s.indexOf('_', i);
                if (pos_ != -1) {
    
    
                    command = s.substring(i, pos_);
                    i = pos_;
                } else {
    
    
                    command = s.substring(i);
                    i = s.length();
                }
            }
            if (!"".equals(command)) {
    
    
                commands.add(command);
            }
        }

        if (k < commands.size()) {
    
    
            commands.set(k, "******");
            StringBuilder builder = new StringBuilder();
            commands.forEach(x -> builder.append(x).append("_"));
            return builder.substring(0, builder.length() - 1);
        } else {
    
    
            return "ERROR";
        }
    }
}

最低位排序

  • 给定一个非空数组(列表),整数元素,
  • 按照元素十进制最低位从小到大进行排序,
  • 十进制最低位相同的元素,相对位置保持不变,
  • 当元素为负值时,十进制最低位等同于去除符号后对应十进制最低位。

输入描述:
给定一个非空数组(列表),其元素数据类型为32位有符号整数
数组长度为[1,1000]
输出描述:
输出排序后的数组

示例一
输入
1,2,5,-21,22,11,55,-101,42,8,7,32
输出
1,-21,11,-101,2,22,42,32,5,55,7,8

思路:

  • 定义比较两个数据的规则函数,以个位数比较大小;
  • 冒泡排序或者快速排序
    python实现
def comp_two_num(n1, n2):
    # 负数去符号
    n1 = abs(n1)
    n2 = abs(n2)

    n1_ = n1 % 10
    n2_ = n2 % 10

    return n1_ > n2_


if __name__ == '__main__':
    alist = list(map(int, input().strip().split(",")))
    n = len(alist)
    for i in range(n-1):
        for j in range(n-1-i): # 冒出最大值        # for j in range(i+1, n) 冒出最小值
            if comp_two_num(alist[j], alist[j+1]):
                alist[j], alist[j+1] = alist[j+1], alist[j]

    print(alist)
    str_alist = list(map(str, alist))
    print(",".join(str_alist))

java实现

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;


public class Main0025 {
    
    

  public static final String COMMA = ",";

  public static void main(String[] args) {
    
    

    try (Scanner scanner = new Scanner(System.in)) {
    
    
      String line = scanner.nextLine();
      solution(line);
    }
  }

  private static void solution(String line) {
    
    
    String[] nums = line.split(COMMA);
    List<Integer> list = new ArrayList<>();
    for (String num : nums) {
    
    
      list.add(Integer.parseInt(num));
    }
    list.sort(new Comparator<Integer>() {
    
    
      @Override
      public int compare(Integer o1, Integer o2) {
    
    
        return getKey(o1) - getKey(o2);
      }

      public Integer getKey(int i) {
    
    
        i = i > 0 ? i : -i;
        return i % 10;
      }
    });

    for (int i = 0; i < list.size(); i++) {
    
    
      System.out.print(list.get(i));
      if (i != list.size() - 1) {
    
    
        System.out.print(COMMA);
      }
    }
  }
}

选座位

  • 座位有一排共n个座位,编号分别为[0…n-1];
  • 员工一个接着一个进入会议室,并且任何时候可以离开;
  • 一个员工进入时,要坐到最大社交距离的座位

例如:
位置A与左右有员工落座的位置距离分别为3和2
位置B与左右有员工落座的位置距离分别为2和3
则认为A、B是等效的座位,影响因素取最小的距离(即为当前座位的最大的社交距离)。
如果有多个这样的座位,则坐到索引最小的那个座位

输入:
第一行 座位数n;
第二行 进出场状态,1进场,-4表示座位4的人离场,0座位的人不离开。

输出:
最后进来的员工,坐在第几个位置?
如果位置已满 则输出-1

示例一
输入
10
[1,1,1,1,-4,1] 最后一个1表示最后进来的人
输出
5

说明
第一个入场的人坐在任何位置都行,但要索引最小的位置,即座位0;
第二个入场的人坐在位置9,与第一个人距离最远;
第三个人可以坐在位置4或者5,因为4与5是等效的座位,取索引最小,故4;

第四个人选择座位2
位置2与0和4的距离位置为(2和2)
位置6与4和9的距离位置为(2和3)
位置7与4和9的距离位置为(3和2)
影响因素都为两个位置,按照要求需索引最小的座位
所以座位2

4号座位员工离开

最后进来的员工最后坐在5号座位

python实现

def solution():
    pass


if __name__ == '__main__':
    n = int(input().strip())
    state_list = eval(input().strip())
    seat_dict = {
    
    }
    seat_list = [i for i in range(n)]

java

import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;


public class Main0113 {
    
    
  public static void main(String[] args) {
    
    
    try (Scanner scanner = new Scanner(System.in)) {
    
    
      int n = Integer.parseInt(scanner.nextLine());
      String seatOrLeave = scanner.nextLine();

      String[] split = seatOrLeave
          .substring(1, seatOrLeave.length() - 1)
          .split(",");

      int[] sol = new int[split.length];
      for (int i = 0; i < split.length; i++) {
    
    
        sol[i] = Integer.parseInt(split[i]);
      }

      int[] seats = new int[n];

      int res = 0;
      for (int action : sol) {
    
    
        if (checkFull(seats, action)) {
    
    
          System.out.println(-1);
          return;
        }
        res = solution(seats, action);
      }
      System.out.print(res);
    }
  }

  private static boolean checkFull(int[] seats, int action) {
    
    
    if (action == 1) {
    
    
      int sum = 0;
      for (int seat : seats) {
    
    
        sum += seat;
      }
      return sum == seats.length;
    }
    return false;
  }

  private static int solution(int[] seats, int action) {
    
    
    if (action == 1) {
    
    
      //位置零
      if (seats[0] == 0) {
    
    
        seats[0] = 1;
        return 0;
      } else {
    
    
        List<Seat> list = new LinkedList<>();
        for (int i = 1; i < seats.length; i++) {
    
    
          if (seats[i] != 1) {
    
    
            int l = i - 1, r = i + 1;
            while (l >= 0 && seats[l] != 1) l--;
            while (r < seats.length && seats[r] != 1) r++;
            if (r == seats.length) r = Integer.MAX_VALUE;
            list.add(new Seat(i, i - l, r - i));
          }
        }
        list.sort(Seat::compareTo);
        int n = list.get(0).n;
        seats[n] = 1;
        return n;
      }
    } else {
    
    
      //离开
      seats[Math.abs(action)] = 0;
      return -4;
    }
  }

  static class Seat implements Comparable<Seat> {
    
    
    public int n;
    public int l;
    public int r;

    public Seat(int n, int l, int r) {
    
    
      this.n = n;
      this.l = l;
      this.r = r;
    }

    @Override
    public int compareTo(Seat o) {
    
    
      // 左右最小值
      int min1 = Math.min(this.l, this.r);
      int min2 = Math.min(o.l, o.r);
      if (min1 != min2) {
    
    
        return min2 - min1;
      } else {
    
    
        return this.n - o.n;
      }
    }
  }
}

路灯照明

路灯照明
题目描述
在一条笔直的公路上安装了N个路灯,
从位置0开始安装,路灯之间间距固定为100米
每个路灯都有自己的照明半径
请计算第一个路灯和最后一个路灯之间,
无法照明的区间的长度和。

输入描述
第一行为一个数N,表示路灯个数,1 <= N <= 100000
第二行为N个空格分割的数,表示路灯的照明半径,1 <= 照明半径

输出描述
无法照明的区间的长度和。

示例一
输入
2
50 50
输出
0
说明
路灯1覆盖0-50 路灯二覆盖50-100
路灯1和路灯2 之间(0-100米)无未覆盖的区间

java

import java.util.Scanner;


public class Main0093 {
    
    
  public static void main(String[] args) {
    
    
    try (Scanner scanner = new Scanner(System.in)) {
    
    
      int n = scanner.nextInt();
      int[] ints = new int[n];
      for (int i = 0; i < n; i++) {
    
    
        ints[i] = scanner.nextInt();
      }
      solution(ints);
    }
  }

  private static void solution(int[] ints) {
    
    

    byte[] bytes = new byte[(ints.length - 1) * 100];

    for (int i = 0; i < ints.length; i++) {
    
    
      int pos = i * 100;
      int left = Math.max(pos - ints[i], 0);
      int right = Math.min(pos + ints[i], bytes.length);

      for (int k = left; k < right; k++) {
    
    
        bytes[k] = 1;
      }
    }

    int count = 0;
    for (byte b : bytes) {
    
    
      if (b == 0) count++;
    }
    System.out.println(count);

  }
}

猜你喜欢

转载自blog.csdn.net/weixin_45228198/article/details/132329019