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

喊七游戏

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

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

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

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

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

示例一
输入:
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

思路:

  • 根据输入序列
    • 得到总人数 n;
    • 求和得到所有的“过”的次数 total_count;
    • 字典存储每人喊‘过’的次数;key -> 0-n
  • 喊数从start=1开始,不断循环
    • 判断start是否满足含有7或者是7的倍数,满足则给对应的人(start%n)喊‘过’次数+1,且cur_count +=1(初始为0)
    • 如果cur_count < total_count ,即还没达到喊‘过’的总次数,start += 1 && continue
    • 否则break
  • 最后将数据按照1-n的顺序放入列表,并依次输出 ;
  • 注意无法直观地排序。

python实现

# 思路中的方法:
class SaySeven:
    def solution(self, pass_list):
        # 总人数
        n = len(pass_list)
        # 总计喊 ‘过’的次数
        total_count = sum(pass_list)
        cur_count = 0
        # 每人喊‘过’的次数
        times_by_person = { i: 0 for i in range(n)}

        # 从1开始喊
        start = 1
        while True:
            if '7' in str(start) or start % 7 == 0:
                key = start % n
                times_by_person[key] += 1
                cur_count += 1

            # 喊‘过’的次数 尚未达到总数
            if cur_count < total_count:
                start += 1
                continue
            else:
                break

        # 从1-n 顺序输出喊‘过’的次数
        result = [0] * n
        for key in times_by_person.keys():
            if key != 0:
                result[key-1] = times_by_person.get(key)
            else:
                val = times_by_person.get(key)
                key = key + n - 1
                result[key] = val

        print(" ".join(list(map(str, result))))


if __name__ == '__main__':
    say_seven = SaySeven()
    while True:
        try:
            pass_list = list(map(int, input("输入喊过次数:").strip().split()))
            say_seven.solution(pass_list)
        except KeyboardInterrupt:
            break

# 方法二,先计算出最高喊到几,才满足喊‘过’的总次数;
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

# 依次喊数,遇过则对应列表索引+1
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 标志位只能为Y or N;

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

实例三:
输入:
5/Y 7/N 3/N 2/Y 10/Y 6/N
输出:
2 3 5 10
6 7

思路:

  • 判断输入是否有效,无效输出ERROR;
    • 学生编号在(0-999)
    • 是否同班标志为Y or N;
    • 必须一个 / 分割;
  • 班级以字典表示,0班,1班;
    • 0:[ ] , 1: [ ]
    • label 表示前一个学生的班级,默认为0;
    • label = (label + 1) % 2 表示班级的切换;
    • 第一个学生直接加入0班级,从第二个学生开始遍历,判断是否与前一个学生同班,相同则直接追加到label表示的班级;否则label切换,并存入切换后的班级;
  • 最终对两个班级的学生编号排序,并输出;

python实现:

# __author__ = "laufing"
#
# 1N 2/Y 3/N 4/Y
# ERROR

# 5/Y 7/N 3/N 2/Y 10/Y 6/N
#  2 3 5 10
#  6 7


class FindSameClass:
    def solution(self, stu_list):
        # 判断是否有效
        if self.invalid(stu_list):
            print("ERROR")
            return

        # 有效则开始查找 1/N 2/Y 3/N 4/Y
        cur_classes = {0: [], 1: []}
        label = 0 # 表示前一个学生的班级
        cur_classes.get(label).append(int(stu_list[0].split("/")[0]))
        for stu in stu_list[1:]:
            # stu like '1/N'
            stu_id, flag = stu.split("/")
            if flag == "Y":
                cur_classes.get(label).append(int(stu_id))
            else:
                label = (label + 1) % 2
                cur_classes.get(label).append(int(stu_id))
        class_0 = sorted(cur_classes.get(0))
        class_1 = sorted(cur_classes.get(1))

        if class_0[0] <= class_1[0]:
            [print(i, end=" ") for i in class_0]
            print("")
            [print(i, end=" ") for i in class_1]
        else:
            [print(i, end=" ") for i in class_1]
            print("")
            [print(i, end=" ") for i in class_0]

    def invalid(self, stu_list):
        if stu_list:
            result = list(filter(self.func, stu_list))
            return len(result) < len(stu_list)
        return True

    def func(self, stu):
        # 过滤出有效的学生编号
        try:
            stu_id, flag = stu.split("/")
            return 0 < int(stu_id) < 999 and flag in ("Y", "N")
        except:
            return False


if __name__ == '__main__':
    find_same_class = FindSameClass()
    while True:
        try:
            stu_list = input("输入:").strip().split()

            find_same_class.solution(stu_list)
        except KeyboardInterrupt:
            break

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

示例四
输入:
5 5 6 6 7 7 8 8 9 9 J K A
输出:
5 6 7 8 9
5 6 7 8 9

思路:

  • 牌面字符列表删除所有的’2’(因为 ‘2’ 对顺子无用);

  • 剩余的牌,从小到大排序得到 sorted_cards列表;

  • while len(set(sorted_cards)) >=5:

    • while sorted_cards:
      • 弹出一个数据data=sorted_cards.pop(0);
      • 如果cur_seq列表为空,则直接追加;否则判断data与cur_seq[-1]的差值,差值为1则追加,差值为0则为重复的牌,将重复的牌追加到repeated_cards列表;
      • 差值大于1,说明顺子肯定断裂,则将data重新插入到sorted_cards的首位;并判断cur_seq中所有牌是否组成顺子(length >=5 ), 若已组成顺子,则将其保存到result列表中,temp重新创建空列表; 若没有组成顺子,则直接清空temp列表。
    • 内层循环结束,判断cur_seq中是否为顺子,是则存入result列表;否则清空;
    • repeated_cards 重新放入sorted_cards,并清空repeated_cards;
  • 最后输出结果

    • result 列表有值,则判断是一个还是两个顺子,两个顺子时,需按照首张牌从小到大按行输出;
    • result 为空,则输出No

python实现:


# __author__ = "laufing"
import random


class DouDZ:
    def __init__(self):
        self.mapping = { # 字符比较大小
            "J": 11,
            "Q": 12,
            "K": 13,
            "A": 14
        }

    def solution(self, card_list):
        # 从小到大排序
        cadidates = sorted(card_list, key=lambda i: self.mapping.get(i) if i in self.mapping else int(i))
        result = []
        cur_seq = []
        repeated_card = []
        while len(set(cadidates)) >= 5: # 去重后 长度>=5
            while cadidates:
                data = cadidates.pop(0)
                if not cur_seq:
                    cur_seq.append(data)
                # 当前值与前一个比较
                elif self.calc_diff(cur_seq[-1], data) == 1:
                    cur_seq.append(data)
                elif self.calc_diff(cur_seq[-1], data) == 0:
                    repeated_card.append(data)
                else:
                    cadidates.insert(0, data)
                    # 出现非连续,判断当前是否组成顺子
                    if len(cur_seq) >= 5:
                        result.append(cur_seq.copy())
                    cur_seq.clear()

            # cadidates 空时判断
            if len(cur_seq) >= 5:
                result.append(cur_seq.copy())
            cur_seq.clear()
            cadidates.extend(repeated_card)
            repeated_card.clear()

        self.print_result(result)

    # 输出结果,多个(2个)顺子 按照顺子的首个数字从小到大依次输出
    def print_result(self, result):
        if len(result) == 1:
            print(" ".join(result[0]))
            return
        elif len(result) == 0:
            print("NO")
            return
        else:
            result = sorted(result, key=lambda i: self.mapping.get(i[0]) if i[0] in self.mapping else int(i[0]))
            for i in result:
                print(" ".join(i))

    def calc_diff(self, pre, cur): # 计算差值
        a = self.mapping.get(pre) if pre in self.mapping else int(pre) # 字符数字
        b = self.mapping.get(cur) if cur in self.mapping else int(cur)
        return b - a


def dispatch_card(): # 随机发牌
    all_cards = [
        "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"
    ]
    cards = []
    while len(cards) < 13:
        card = random.choice(all_cards)
        if cards.count(card) < 4:
            cards.append(card)

    return cards


if __name__ == '__main__':
    dou_dz = DouDZ()
    while True:
        try:
            card_list = input("输入:").strip().split()
            # card_list = dispatch_card()
            print("card_list:", card_list)

            # 删除2  2不能构成顺子
            while "2" in card_list:
                card_list.remove("2") #

            # 找出顺子
            dou_dz.solution(card_list)

        except KeyboardInterrupt:
            break

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));
    }
  }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

laufing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值