算法练习- 其他算法练习2

喊七游戏

  • N个人围成一圈,按顺时针从1 - 7编号

  • 编号为1的人从1开始喊数,下一个人喊得数字是上一个人喊得数字+1,
    当将要喊出数字7的倍数或者含有7的话,不能喊出,而是要喊过。

  • 假定N个人都没有失误,当喊到数字k时,可以统计每个人喊“过"的次数。

  • 现给定一个长度N的数组,存储打乱的每个人喊”过"的次数,请把它还原成正确顺序。
    即数组的第i个元素存储编号i的人喊“过“的次数

输入:
每个人喊过的次数(乱序),空格分隔
输出:
顺序正确的喊 ‘过’ 的次数,空格分隔

示例一
输入:
0 1 0
输出:
1 0 0

输入:
0 0 0 2 1
输出
0 2 0 1 0 输出每个值,并空格隔开
说明
一共3次喊过
发生在7 14 17
编号为2的遇到7 17
编号为4的遇到14

思路:

  • 求和所有的“过”的次数,推测出最少的k值;
  • 根据k值正向计算每个人喊的次数;i%n - 1 得索引
  • 无法直接排序。

python实现

def predict_k(total_times):
    """ predict value of k """
    pre_times = 0
    k = 1  # 从1开始
    while pre_times != total_times:
        pre_times = 0
        k += 1
        for i in range(1, k+1):
            if i % 7 == 0 or '7' in str(i):
                pre_times += 1
    return k


def skip_times_by_person(n, k, origin):
    for i in range(1, k + 1):
        if i % 7 == 0 or "7" in str(i):
            # 过
            if i % n != 0:
                idx = i % n
                idx -= 1
                origin[idx] += 1
            else:
                origin[-1] += 1
    return origin


if __name__ == '__main__':
    skip_times_list = list(map(int, input().strip().split()))
    # 人数
    n = len(skip_times_list)
    # 总的‘过’次数
    total_times = sum(skip_times_list)
    # 预测k值
    k = predict_k(total_times)
    print("current k:", k)
    # 原始每个人喊‘过’的次数均为0
    origin = [0 for i in range(n)]

    # 1-k 每个人喊‘过’的次数
    skip_times_by_person(n, k, origin)

    for i in origin:
        print(i, end=" ")

java实现

import java.util.Scanner;


public class Main0016 {
    
    
  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[] split = line.split(" ");
    int sum = 0;
    for (String s : split) {
    
    
      sum += Integer.parseInt(s);
    }

    int[] res = new int[split.length];

    int j = 0;
    for (int i = 1; i < 300; i++, j++) {
    
    
      if (j == split.length) j = 0;
      if (i % 7 == 0 || (i + "").contains("7")) {
    
    
        res[j] += 1;
      }
      int sum1 = 0;
      for (int re : res) sum1 += re;
      if (sum == sum1) break;
    }

    for (int i = 0; i < res.length; i++) {
    
    
      System.out.print(res[i]);
      if (i != res.length - 1) {
    
    
        System.out.print(" ");
      }
    }
  }
}

找出同班的小朋友

  • 两个班的小朋友排队时混在了一起,每个小朋友知道自己与前面一个小朋友是不是同班;
  • 帮忙把同班的小朋友找出来,小朋友的编号为整数;
  • 与前面一个小朋友同班用Y表示,不同班用N表示

输入:
小朋友编号 / 是否同班
比如 6/N 2/Y 3/N 4/Y 共4位小朋友
6和2是同班,2和3不同班,3和4同班
0 < 小朋友编号 < 999

输出:
每一行是同一个班小朋友的编号升序排列 且用空格分开;
首个小朋友编号小的班级在第一行输出;
如果输入不符合要求输出字符串ERROR

示例一
输入:
1/N 2/Y 3/N 4/Y
输出:
1 2
3 4
说明
2的同班标记为Y因此和1同班
3的同班标记位N因此和1,2不同班
4的同班标记位Y因此和3同班

实例二:
输入:
a/N 2/Y 3/N 4/Y
输出:
ERROR

思路:

  • 判断输入是否有效,无效输出ERROR;
  • cls1 cls2两个班级列表;
  • 双指针,前一个指针表示前一个小朋友的班级,后一个指针表示当前小朋友;
  • 前一个指针在两个班级中切换
  • 是否两个班级? 谁先输出【首个编号小的班级】、谁后输出。

python实现:

def is_valid(friends):
    if len(friends) < 1:
        return False
    for i in friends:
        try:
            if "/" not in i:
                return False
            a, b = i.split("/")
            if not a.isdigit() or not b in ["Y", "N"]:
                return False
        except:
            return False
    return True


if __name__ == '__main__':
    friends = input().strip().split()
    n = len(friends)
    cls1 = []
    cls2 = []
    if is_valid(friends): # 有效输入
        # 假设第一个小朋友为cls1班级
        pre = cls1
        cls1.append(int(friends[0].split("/")[0]))
        for i in range(1, n):
            if friends[i].endswith("Y"):
                pre.append(int(friends[i].split("/")[0]))
            else:
                if pre is cls1:
                    pre = cls2
                else:
                    pre = cls1
                pre.append(int(friends[i].split("/")[0]))

        cls1.sort()
        cls2.sort()
        # 只有一个班级  或者 两个班级
        if cls1 and cls2:
            if cls1[0] < cls2[0]: # 数值比较, 字符串是逐字符比较,与整数比较有偏差
                for i in cls1:
                    print(i, end=" ")
                print("\n", end="")
                for i in cls2:
                    print(i, end=" ")
            else:
                for i in cls2:
                    print(i, end=" ")
                print("\n", end="")
                for i in cls1:
                    print(i, end=" ")
        elif cls1:
            for i in cls1:
                print(i, end=" ")
        else:
            for i in cls2:
                print(i, end=" ")

    else:
        # 无效输入
        print("ERROR")

java实现:

import java.util.Scanner;
import java.util.TreeSet;

public class Main0038 {
    
    
  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[] stus = line.split(" ");
    try {
    
    
      TreeSet<Integer> c1 = new TreeSet<>();
      TreeSet<Integer> c2 = new TreeSet<>();

      boolean is1 = true;
      for (int i = 0; i < stus.length; i++) {
    
    
        String[] split = stus[i].split("/");
        String id = split[0];
        String same = split[1];
        if (i == 0) {
    
    
          c1.add(Integer.parseInt(id));
          continue;
        }
        if ("N".equals(same)) is1 = !is1;
        (is1 ? c1 : c2).add(Integer.parseInt(id));
      }

      StringBuilder b1 = new StringBuilder();
      for (Integer id : c1) b1.append(id).append(" ");


      if (c2.size() > 0) {
    
    
        StringBuilder b2 = new StringBuilder();
        for (Integer id : c2) b2.append(id).append(" ");
        if (c1.first() < c2.first()) {
    
    
          System.out.println(b1.toString().trim());
          System.out.println(b2.toString().trim());
        } else {
    
    
          System.out.println(b2.toString().trim());
          System.out.println(b1.toString().trim());
        }
      } else {
    
    
        System.out.println(b1.toString().trim());
      }

    } catch (Exception e) {
    
    
      System.out.println("ERROR");
    }
  }
}

斗地主

游戏中,扑克牌由小到大的顺序为3 4 5 6 7 8 9 10 J Q K A 2
玩家可以出的扑克牌阵型有,单张,对子,顺子,飞机,炸弹等
其中顺子的出牌规则为,由至少5张由小到大连续递增的扑克牌组成
且不能包含2
例如:{3,4,5,6,7}、{3,4,5,6,7,8,9,10,J,Q,K,A}都是有效的顺子
而{J,Q,K,A,2}、{2,3,4,5,6}、{3,4,5,6}、{3,4,5,6,8}等都不是顺子
给定一个包含13张牌的数组,如果有满足出牌规则的顺子,请输出顺子
如果存在多个顺子,请每行输出一个顺子
且需要按照顺子的第一张牌的大小(必须从小到大)依次输出
如果没有满足出牌规则的顺子,请输出No

输入:
13张扑克牌,空格隔开,
每张扑克牌的数字都是合法的,并且不包括大小王:2 9 J 2 3 4 K A 7 9 A 5 6
不需要考虑输入为异常字符的情况
输出:
组成的顺子 3 4 5 6 7

示例一
输入:
2 9 J 2 3 4 K A 7 9 A 5 6
输出:
3 4 5 6 7

示例二
输入:
2 9 J 10 3 4 K A 7 Q A 5 6
输出:
3 4 5 6 7
9 10 J Q K A

示例三
输入:
2 9 9 9 3 4 K A 10 Q A 5 6
输出:
No

思路:

  • 遍历正常大小顺序的每张牌,得到 i;

  • i不是2且i在自己的牌中,则将当前牌追加到一个temp列表,追加时与前一张牌比较是否连续;

    • 连续则追加;
    • 否则,判断之前的所有牌是否组成顺子(length >=5 ), 若已组成顺子,则将其保存到result列表中,temp重新创建空列表并追加 i; 若没有组成顺子,则直接清空temp列表,并追加i。
  • 循环结束时,判断temp中是否为顺子,是则存入result列表。

  • 以上封装一个函数,并执行两次。覆盖(5 5 6 6 7 7 8 8 9 9 J K A)重复顺子的情况。

  • 最后输出结果

    • result 列表有值,则判断是一个还是两个顺子
    • result 无值,则输出No

python实现:


def calc_diff(a, b):
    """ 计算两个字符的差值 """
    if a.isdigit() and b.isdigit():
        return abs(int(a) - int(b))
    if (b, a) in [("10", "J"), ("J", "Q"), ("Q", "K"), ("K", "A")]:
        return 1
    else:
        return 2


def solution(origin):
    n = len(origin)
    if n < 5:
        return
    temp = []
    for i in normal: # str
        if i != "2" and i in origin:
            if not temp:
                temp.append(i)
                origin.remove(i)
            else:
                # 当前值与前一个值是否连续
                if calc_diff(i, temp[-1]) == 1:
                    temp.append(i)
                    origin.remove(i)
                else:
                    # 不连续时,前面不是顺子的情况下要清空
                    if len(temp) < 5:
                        temp.clear()
                        temp.append(i)
                    else:
                        result.append(temp)
                        temp = []
                        temp.append(i)
    # 最后一次的追加
    if len(temp) >= 5:
        result.append(temp)


if __name__ == '__main__':
    normal = "3 4 5 6 7 8 9 10 J Q K A 2".split()

    # origin = "2 9 J 2 3 4 K A 7 9 A 5 6".split()
    origin = input().strip().split()
    result = []

    # 最多有两个顺子
    solution(origin)
    solution(origin)

    if result:
        # 有顺子
        if len(result) == 1:
            print(" ".join(result[0]))
        elif len(result) > 1:
            result_ = sorted(result, key=lambda i: int(i[0]))
            for i in result_:
                print(" ".join(i))
    else:
        # 没有顺子
        print("No")

java实现:

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

public class Main0117 {
    
    
  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[] split = line.split(" ");
    String[] index = new String[13];
    convert(split, index);

    List<String> resSet = new LinkedList<>();
    for (int i = 1; i < index.length; i++) {
    
    
      int count = 0;
      StringBuilder builder = new StringBuilder();
      while (i < index.length && index[i] != null) {
    
    
        builder.append(index[i]).append(" ");
        count++;
        i++;
      }
      if (count >= 5) {
    
    
        resSet.add(builder.substring(0, builder.length() - 1));
      }
    }

    if (resSet.size() == 0) {
    
    
      System.out.println("No");
    } else {
    
    
      for (String res : resSet) {
    
    
        System.out.println(res);
      }
    }

  }

  private static void convert(String[] split, String[] ints) {
    
    
    for (String str : split) {
    
    
      if (str.length() == 1) {
    
    
        char c = str.charAt(0);
        if (Character.isDigit(c)) {
    
    
          ints[Character.digit(c, 10) - 2] = str;
        } else {
    
    
          switch (c) {
    
    
            case 'A':
              ints[12] = str;
              break;
            case 'J':
              ints[9] = str;
              break;
            case 'Q':
              ints[10] = str;
              break;
            case 'K':
              ints[11] = str;
              break;
            default:
              break;
          }
        }
      } else {
    
    
        ints[8] = str;
      }
    }
  }
}

补种胡杨

某沙漠新种植 N 棵胡杨(编号 1-N ),排成一排,一个月后,有 M 棵胡杨未能成活。
现可补种胡杨 K 棵,请问如何补种(只能在原来的位置补种),可以得到最多的连续胡杨树?

输入:
N 总种植数量,1≤N≤100000
M 未成活胡杨数量,1≤M≤N
未成活的编号,从小到大排序
K 最多可以补种的数量,0≤K≤M

输出:
最多的连续胡杨棵数

示例一
输入:
5
2
2 4
1
输出
3
说明
补种到2或4结果一样,最多的连续胡杨棵树都是3。

示例二
输入
10
3
2 4 7
1
输出
6
说明
补种第7棵树,最多连续胡杨树棵数位6(5,6,7,8,9,10)

思路:

  • 未成活的胡杨树之间距离越远,补种获取的连续棵数才可能越大;且必须连续补种。
  • 补种k=1时,分别获取补种最左边1棵、补种中间1棵、补种最右边1棵的情况下的最大连续数;
  • 补种k=2时,分别获取补种最左边2棵、补种中间2棵、补种最右边2棵的情况下的最大连续数;
  • 总结规律,得到补种索引为range(m-k+1)
    • 当补种索引为0,即最左边补种k棵时,取max(cur_max, dead[i+k] - 1)
    • 当补种索引为最后一次,即最右边补种k棵 ,取max(cur_max, n - dead[i-1])
    • 当补种中间的k棵时,取max(cur_max, dead[i+k] - dead[i-1] - 1)

python实现:

def solution(n, m, indies, k):
    """ 必须连续地补未活的树 """
    max_len = 0

    # 控制补树的索引
    for i in range(m - k + 1): # k为1、2、3.......
        if i == 0: # 补最左边上的k个
            max_len = max(max_len, indies[i + k] - 1)
        elif i == m - k: # 补最右边的k个
            max_len = max(max_len, n - indies[i - 1])
        else:
            max_len = max(max_len, indies[i + k] - indies[i - 1] - 1)

    return max_len


if __name__ == '__main__':

    n, m = int(input().strip()), int(input().strip())
    m_id_list = list(map(int, input().strip().split()))
    k = int(input().strip())

    print(solution(n, m, m_id_list, k))

java实现:

import java.util.Scanner;

public class Main0256 {
    
    
  public static void main(String[] args) {
    
    
    try (Scanner scanner = new Scanner(System.in)) {
    
    
      int N = scanner.nextInt();
      int M = scanner.nextInt();

      int[] indies = new int[M];
      for (int i = 0; i < M; i++) {
    
    
        indies[i] = scanner.nextInt();
      }

      int K = scanner.nextInt();
      System.out.println(solution(N, M, indies, K));
    }

  }

  public static int solution(int n, int m, int[] indies, int k) {
    
    
    int maxLen = 0;

    for (int i = 0; i <= m - k; i++) {
    
    
      if (i == 0) {
    
    
        maxLen = Math.max(maxLen, indies[i + k] - 1);
      } else if (i == m - k) {
    
    
        maxLen = Math.max(maxLen, n - indies[i - 1]);
      } else {
    
    
        maxLen = Math.max(maxLen, indies[i + k] - indies[i - 1] - 1);
      }
    }
    return maxLen;
  }
}

ip地址转为整数

  • 如 128#0#255#255 为一个虚拟IP,转换为32位整数的结果为2147549183;1#0#0#0,转换为32位整数的结果为16777216
  • 现以字符串形式给出一个虚拟IPv4地址,每一节范围分别为(1~128)#(0~255)#(0~255)#(0~255),
    每个IPv4地址只能对应到唯一的整数上。
    如果是非法虚拟IP,输出invalid IP
  • 需对非法虚拟IP(空串,含有IP地址中不存在的字符,数值超限)进行识别,输出invalid IP

输入:
虚拟IPv4地址格式字符串
输出:
转换的整型

示例一
输入:
100#101#1#5
输出:
1684340997

示例一
输入:
1#2#3
输出:
invalid IP

思路:

  • 验证虚拟IP的有效性;
  • 字符串以#分割,并映射为int,每个整数使用bin转为二进制,并截取(0b不要)拼接出一个八位的二进制;
  • 所有二进制依次拼接成一个32位的二进制字符串;
  • 32位字符串截取出从1开始的部分,并转为整数(加权求和)。

python实现:

def is_valid(s):
    if not s:
        return False
    if "#" not in s:
        return False
    try:
        a, b, c, d = s.split("#")
    except:
        return False

    # 不是数值情况
    if not a.isdigit() or not b.isdigit() or not c.isdigit() or not d.isdigit():
        return False

    # 数值不在范围内
    if not 128 >= int(a) >= 1 or not 255 >= int(b) >= 0 or not 255 >= int(c) >= 0 or not 255 >= int(d) >= 0:
        return False

    return True


def bin_str_to_int(bin_str):
    idx = bin_str.find("1")
    if idx == -1:
        return 0

    int_val = 0
    s = bin_str[idx:]
    s_len = len(s)
    base = 2**(s_len - 1)
    for i in s:
        # 每个字符
        if i == "1":
            int_val += 1 * base
        base /= 2

    return int_val


if __name__ == '__main__':
    # s = "128#0#255#255"
    s = input()
    if is_valid(s):
        # 有效的IP
        data_list = map(int, s.split("#"))
        bin_str = ""
        for v in data_list:
            temp_bin = bin(v)[2:]
            if len(temp_bin) < 8:
                temp_bin = "0" * (8 - len(temp_bin)) + temp_bin

            bin_str += temp_bin

        int_val = bin_str_to_int(bin_str)
        print(int(int_val))

    else:
        # 无效的IP
        print("invalid IP")

java实现:

import java.util.Scanner;

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

  private static void solution(String ip) {
    
    
    String[] strings = ip.split("#");
    int len = strings.length;
    long count = 0;
    boolean isF = true;

    if (len == 4) {
    
    
      for (int i = 0; i < len; i++) {
    
    
        long n = Integer.parseInt(strings[i]);
        if (i == 0 && (n < 1 || n > 128)) {
    
    
          isF = false;
          break;
        } else if (n < 0 || n > 255) {
    
    
          isF = false;
          break;
        }
        count += n << (8 * (3 - i));
      }
    } else {
    
    
      isF = false;
    }

    if (isF) {
    
    
      System.out.print(count);
    } else {
    
    
      System.out.print("invalid IP");
    }
  }
}

响应报文的时间

  • HOST收到查询报文,解析出最大响应时间后,需要在MaxResponseTime(s) 回应一个响应报文;

  • 在响应上一个报文前,若收到一个新的查询报文,则取两者最大时间的最小值,返回响应;

  • 每个查询报文的最大响应时间计算:
    当MaxRespCode < 128, MaxRespTime = MaxRespCode;
    当MaxRespCode >= 128, MaxRespTime = (mant | 0x10) << (exp + 3);
    如下解释:
    MaxRespCode转为二进制 为10000000
    |1|000|0000|
    |1|exp|mant|
    mant为MaxRespCode的低四位,exp为高5-7位;
    MaxRespCode 【0, 255】;

输入:
第一行为查询报文个数 C,
后续每行分别为HOST收到报文时间T,MaxRespCode M
输出:
HOST发送响应报文的时间

示例一
输入:
3
0 20
1 10
8 20
输出
11
说明:
第0s收到1个报文,其MaxRespCode为20秒(<128),MaxRespTime则为20s,故要到0+20=20s 返回响应;

第1s收到第2个报文,MaxRespCode为10,MaxRespTime则为10s,
故要到1+10=11s响应,与上个报文的响应时间比较,得最小值为11s;

第8s收到第3个报文,MaxRespCode为20,MaxRespTime则为20s,则要到8+20=28s响应,与上个响应取最小值为11s

故输出 11

 
示例二
输入:
2
0 255
200 60
输出:
260

说明
第0s 收到第1个报文,MaxRespCode 为255s,MaxRespTime则为(15|0x10)<<(7+3)=31744s ,(mant=15, exp=7) ; 则在0+31744s 返回响应。

第200s 收到第2个报文,MaxRespCode 为60s,MaxRespTime为60s,则要到200+60=260秒响应,与上个报文取最小值 为260s 。

思路:

  • MaxRespCode是否小于128,计算出MaxRespTime,再加上收到报文的时间,就是响应的时间;
  • 所有的响应时间取最小值;

python实现:

def get_int(s):
    idx = s.find("1")
    if idx == -1:
        return 0
    s_ = s[idx:]
    n = len(s_)
    base = 2 ** (n - 1)
    int_val = 0
    for i in s_:
        if i == "1":
            int_val += 1 * base

        base /= 2

    return int(int_val)


def calc_max_resp_time(max_resp_code):
    # 响应code转为二进制
    bin_str = bin(max_resp_code)
    bin_str = bin_str[2:]
    if len(bin_str) < 8:
        bin_str = "0" * (8 - len(bin_str)) + bin_str

    # 整数
    mant = get_int(bin_str[-4:])
    exp = get_int(bin_str[1:4])

    return (mant | 0x10) << (exp + 3)


if __name__ == '__main__':
    # 报文数
    c = int(input().strip())
    package = []
    for i in range(c):
        p = list(map(int, input().strip().split()))
        package.append(p)

    print(package)

    resp_t = 2**32 - 1
    for p in package:
        if p[1] < 128:
            max_resp_time = p[1]

        else:
            max_resp_time = calc_max_resp_time(p[1])

        resp_t = min(resp_t, max_resp_time + p[0])

    print(resp_t)

java实现:

import java.util.Scanner;

public class Main0229 {
    
    
  public static void main(String[] args) {
    
    
    try (Scanner scanner = new Scanner(System.in)) {
    
    
      int C = scanner.nextInt();
      int[] T = new int[C];
      int[] M = new int[C];

      for (int i = 0; i < C; i++) {
    
    
        T[i] = scanner.nextInt();
        M[i] = scanner.nextInt();
      }
      int responseTime = solution(C, T, M);
      System.out.println(responseTime);
    }
  }

  private static int solution(int C, int[] T, int[] M) {
    
    
    int responseTime = 0;
    for (int i = 0; i < C; i++) {
    
    
      int maxRespTime = calculateMaxRespTime(M[i]);
      int newRespTime = T[i] + maxRespTime;

      if (i == 0 || newRespTime < responseTime) {
    
    
        responseTime = newRespTime;
      }
    }

    return responseTime;
  }

  private static int calculateMaxRespTime(int maxRespCode) {
    
    
    if (maxRespCode < 128) {
    
    
      return maxRespCode;
    } else {
    
    
      int exp = (maxRespCode & 0x70) >> 4;
      int mant = maxRespCode & 0x0F;
      return (mant | 0x10) << (exp + 3);
    }
  }
}

事件推送

  • 同一个数轴X上有两类点的集合A={A1, A2, …, Am}和B={B1, B2, …, Bn},
    Ai和Bj均为正整数,A、B已经按照从小到大排好序,A、B均不为空;
  • 给定一个距离R(正整数),
    列出同时满足如下条件的所有(Ai, Bj)数对:
    • Ai <= Bj;
    • Ai, Bj之间的距离小于等于R;
    • 在满足1,2的情况下,每个Ai只取最近的Bj,形成数对;有重复的最近Bj只需第一个。
    • 输出结果按Ai从小到大的顺序排序

输入:
第一行三个正整数m,n,R
第二行m个正整数,表示集合A
第三行n个正整数,表示集合B
1 <= R <= 100000,1 <= n,m <= 100000,1 <= Ai,Bj <= 1000000000

输出:
每个数对输出一行,Ai和Bj以空格隔开

示例一
输入
4 5 5
1 5 5 10
1 3 8 8 20
输出
1 1
5 8
5 8

思路:

  • 遍历A集合,依次组成满足条件的数对;
  • 每个 A i {A_i} Ai只与距离最近的 B j {B_j} Bj组成
  • 所有数对追加到一个列表中;
  • 遍历输出每个数对

python实现:


if __name__ == '__main__':
    m, n, r = list(map(int, input().strip().split()))
    a_list = list(map(int, input().strip().split()))
    b_list = list(map(int, input().strip().split()))

    result = []

    for i in a_list:
        temp = []
        for j in b_list:
            if i <= j and abs(i - j) <= r:
                if not temp:
                    temp.append((i, j))
                else:
                    pre_dist = temp[-1][1] - temp[-1][0]
                    cur_dist = j - i
                    if cur_dist < pre_dist:
                        temp.pop()
                        temp.append((i, j))

        if temp:
            result.extend(temp)

    for p in result:
        print(p[0], " ", p[1])

java实现:

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

public class Main0132 {
    
    
  public static void main(String[] args) {
    
    
    try (Scanner scanner = new Scanner(System.in)) {
    
    
      int m = scanner.nextInt();
      int n = scanner.nextInt();
      int R = scanner.nextInt();
      int[] a = new int[m];
      int[] b = new int[n];

      for (int i = 0; i < m; i++) {
    
    
        a[i] = scanner.nextInt();
      }
      for (int i = 0; i < n; i++) {
    
    
        b[i] = scanner.nextInt();
      }

      solution(R, a, b);
    }
  }

  private static void solution(int R, int[] a, int[] b) {
    
    
    int index = 0;
    List<int[]> list = new ArrayList<>();

    for (int j : a) {
    
    

      int[] ints = new int[2];

      while (index < b.length) {
    
    
        if (j <= b[index] && b[index] - j <= R) {
    
    
          ints[0] = j;
          ints[1] = b[index];
          list.add(ints);
          break;
        }
        index++;
      }
    }

    list.forEach(e -> System.out.println(e[0] + " " + e[1]));
  }
}

&nbsp;

数列还原

  • 有一个数列A[n],A[n+1]都是A[n]的描述数字
  • 其中A[0]=1
    规则如下
    A[0] = 1
    A[1] = 11 表示A[0]从左到右连续出现了1次1
    A[2] = 21 表示A[1]从左到右连续出现了2次1
    A[3] = 1211 表示A[2]从左到右连续出现了一次2,又连续出现了一次1
    A[4] = 111221 表示A[3]从左到右连续出现了一次1又连续出现了一次2又连续出现了2次1

输入:
数字n
输出:
数列第n项 A[n]

示例一
输入:
4
输出:
111221

思路:

  • 依次遍历求A[1]、A[2]、…直到A[n];
  • 在描述前一项时,遍历它的字符串并统计每个数出现了几次;
  • 当出现不一样的数字时,拼接之前统计的count + char到字符串中。

python实现:

def calc_n_item(n):
    pre = "1"
    if n == 0:
        print(pre)
        return
    for i in range(1, n + 1):  # 4
        # 拼接结果
        result = ""
        # pre 代表前一项
        first_char = pre[0] # 前一项的首个字符
        count = 1  # 计数
        for j in range(1, len(pre)):
            if pre[j] == first_char:
                count += 1
            else:
                result += str(count) + first_char
                count = 1
                first_char = pre[j]
        result += str(count) + first_char
        pre = result

    print(result)


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

    calc_n_item(n)

java实现:

import java.util.Scanner;

public class Main {
    
    
    public static void main(String[] args) {
    
    
        try (Scanner scanner = new Scanner(System.in)) {
    
    
            int n = scanner.nextInt();

            solution(n);
        }

    }

    private static void solution(int n) {
    
    

        String content = "1";

        if (n == 0) {
    
    
            System.out.println(content);
            return;
        }

        for (int i = 1; i <= n; i++) {
    
    
            // 字符串构建对象
            StringBuilder next = new StringBuilder();
            char[] chars = content.toCharArray();
            char last = chars[0];
            int count = 1;
            for (int j = 1; j < chars.length; j++) {
    
    
                if (chars[j] == last) count++;
                else {
    
    
                    next.append(count).append(last);
                    count = 1;
                    last = chars[j];
                }
            }
            next.append(count).append(last);
            content = next.toString();
        }

        System.out.println(content);

    }
}

数组组成的最小数字

  • 给定一个整型数组,请从该数组中选择3个元素组成最小数字并输出;
  • 如果数组长度小于3,则选择数组中所有元素来组成最小数字;

输入
数组元素
0 < 数组长度 <= 100,
0 < 整数的取值范围 <= 10000。

输出:
由3个元素组成的最小数字
如果数组长度小于3,则所有元素组成的最小数字。

示例一
输入:
21,30,62,5,31
输出:
21305

示例二
输入
5,21
输出
215

思路:

  • 数组一个元素,则最小数输出元素本身;
  • 数组有两个元素时,则使用这两个元素组成最小数【简单比较即可】;
  • 数组有三个及以上元素时
    • 数组升序排序,并分片出前三个最小的元素;
    • 三个最小元素的数组冒泡升序排序,期间两个元素比较大小规则为谁在前面组成的数值小,即该元素小。
    • 最后将 升序排序后 的三元素 拼接为字符串。

python实现:


def great_than(v1, v2):
    value1 = str(v1) + str(v2)
    value2 = str(v2) + str(v1)
    return int(value1) > int(value2)


def clac_min_val(alist):
    n = len(alist)
    if n == 1:
        print(alist[0])
        return
    elif n == 2:
        # 选择两个元素 组成最小数字
        a, b = alist
        v1 = str(a) + str(b)
        v2 = str(b) + str(a)
        val = v1 if int(v1) < int(v2) else v2
        print(val)
        return

    # 三个及以上的数字
    alist.sort()
    min_list = alist[:3]
    min_list_len = len(min_list)
    for i in range(min_list_len-1):
        for j in range(min_list_len-1-i):
            if great_than(min_list[j], min_list[j+1]):
                min_list[j], min_list[j+1] = min_list[j+1], min_list[j]
    result = ""
    for v in min_list:
        result += str(v)
    print(result)


if __name__ == '__main__':
    # alist = "21,30,62,5,31".split(",")
    alist = input().strip().split(",")
    alist = list(map(int, alist))

    clac_min_val(alist)

java实现:

import java.util.*;

public class Main {
    
    
    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[] split = line.split(",");

        int len = split.length;
        StringBuilder builder = new StringBuilder();

        if (len == 1) {
    
    
            builder = new StringBuilder(split[0]);
        } else {
    
    
            List<String> list = new ArrayList<>();
            int[] ints = new int[len];
            for (int i = 0; i < len; i++) {
    
    
                ints[i] = Integer.parseInt(split[i]);
            }
            Arrays.sort(ints);
            int numsLen;
            if (len == 2) {
    
    
                numsLen = 2;
            } else {
    
    
                numsLen = 3;
            }
            for (int i = 0; i < numsLen; i++) {
    
    
                list.add(String.valueOf(ints[i]));
            }
            Collections.sort(list);
            for (int i = 0; i < numsLen; i++) {
    
    
                builder.append(list.get(i));
            }
        }
        System.out.println(Integer.valueOf(builder.toString()));

    }
}

字符串加密

  • 给你一串未加密的字符串str,通过对字符串的每一个字母进行改变来实现加密,每一个字母str[i] 偏移 数组a[i]的值,
  • 数组a 满足:a[0]=1, a[1]=2, a[2]=4
    当i>=3时,数组元素a[i]=a[i-1]+a[i-2]+a[i-3],
    例如:原文 abcde 加密后 bdgkr,其中偏移量分别是1,2,4,7,13。

输入:
第一行输入整数n(1 <= n <= 1000),表示有n组测试数据
后续每行为一组字符串,只含小写字母, 0 < 长度 <= 50

输出:
每组测试数据输出一行,表示字符串的密文

示例一
输入:
1
xy
输出:
ya

思路:

  • 字符串中的每个字符转为ASCII码,再加 a[i] 对应的偏移量offset;
  • 判断加offset后,对应的ASCII码值是否<=122
    • 是,则转为字符,并拼接到一个新字符串中;
    • 否,则需要%122 + 96 ,然后转为字符,并拼接到新字符串;

python实现:

def get_a_n(n):
    if n == 0:
        return 1
    elif n == 1:
        return 2
    elif n == 2:
        return 4
    else:
        return get_a_n(n-1) + get_a_n(n-2) + get_a_n(n-3)


def encrypt_str(str_list):
    encrypt_result = []
    for str_ in str_list:
        result = ""
        n = len(str_)
        for i in range(n):
            offset = ord(str_[i]) + get_a_n(i)
            # 处理超出问题  z-122
            if offset <= 122:
                result += chr(offset)
            else:
                offset = (offset % 122) + 96
                result += chr(offset)
        encrypt_result.append(result)

    return encrypt_result


if __name__ == '__main__':
    n = int(input().strip())
    origin_strings = []
    for i in range(n):
        origin_strings.append(input().strip())

    en_result = encrypt_str(origin_strings)

    for i in en_result:
        print(i)

java实现:

import java.util.Scanner;

public class Main0094 {
    
    
  public static void main(String[] args) {
    
    
    try (Scanner scanner = new Scanner(System.in)) {
    
    
      int n = Integer.parseInt(scanner.nextLine());
      String[] strings = new String[n];
      for (int i = 0; i < n; i++) {
    
    
        strings[i] = scanner.nextLine();
      }
      solution(strings);
    }
  }

  private static void solution(String[] strings) {
    
    
    int[] a = {
    
    1, 2, 4};
    long[] offsets = new long[50];
    for (int i = 0; i < offsets.length; i++) {
    
    
      if (i < 3) {
    
    
        offsets[i] = a[i];
      } else {
    
    
        offsets[i] = offsets[i - 1] + offsets[i - 2] + offsets[i - 3];
      }
    }

    for (String str : strings) {
    
    
      char[] chars = str.toCharArray();
      for (int i = 0; i < chars.length; i++) {
    
    
        char c = chars[i];
        chars[i] = (char) ((c - 97 + offsets[i]) % 26 + 97);
      }
      System.out.println(new String(chars));
    }
  }
}

猜你喜欢

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