校招算法笔面试 | 校招笔面试真题-小红的顺子

题目## 题目

题目链接

题目链接

小红的顺子

题目描述

小红有一个长度为 n − 1 n-1 n1 的数组,满足 1 ≤ a i ≤ n 1 \leq a_i \leq n 1ain a i < a i + 1 a_i < a_{i+1} ai<ai+1,求顺子的最大长度。

顺子的定义为:对于长度为 m m m 的数组 b b b,如果 b i + 1 = b i + 1 b_i + 1 = b_{i+1} bi+1=bi+1 1 ≤ i < m 1 \leq i < m 1i<m),则称 b b b 是顺子。

输入:

  • 第一行一个整数 n n n,表示数组的长度加1
  • 第二行 n − 1 n-1 n1 个整数,表示严格递增的数组 a a a

输出:

  • 一个整数,表示顺子的最大长度

解题思路

这是一个序列问题,可以通过以下步骤解决:

  1. 首先理解题目特点:

    • 输入数组已经是严格递增的
    • 不需要排序和去重
    • 只需要找到连续递增(差值为1)的最长子序列
  2. 解题策略:

    • 直接遍历数组
    • 检查相邻两个数的差值是否为1
    • 维护最长的连续序列长度
  3. 具体步骤:

    • 遍历数组,检查相邻元素
    • 如果 a [ i ] = a [ i − 1 ] + 1 a[i] = a[i-1] + 1 a[i]=a[i1]+1,则当前连续序列长度加1
    • 否则重新开始计数
    • 维护最大长度

代码

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> a(n - 1);
    for(int i = 0; i < n - 1; i++) {
        cin >> a[i];
    }
    
    int maxLen = 1;  // 最长顺子长度
    int curLen = 1;  // 当前顺子长度
    
    // 遍历寻找连续序列
    for(int i = 1; i < n - 1; i++) {
        if(a[i] == a[i-1] + 1) {
            curLen++;
            maxLen = max(maxLen, curLen);
        } else {
            curLen = 1;
        }
    }
    
    cout << maxLen << endl;
    return 0;
}
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        
        int[] a = new int[n - 1];
        for(int i = 0; i < n - 1; i++) {
            a[i] = sc.nextInt();
        }
        
        int maxLen = 1;  // 最长顺子长度
        int curLen = 1;  // 当前顺子长度
        
        // 遍历寻找连续序列
        for(int i = 1; i < n - 1; i++) {
            if(a[i] == a[i-1] + 1) {
                curLen++;
                maxLen = Math.max(maxLen, curLen);
            } else {
                curLen = 1;
            }
        }
        
        System.out.println(maxLen);
    }
}
n = int(input())
a = list(map(int, input().split()))

max_len = 1  # 最长顺子长度
cur_len = 1  # 当前顺子长度

# 遍历寻找连续序列
for i in range(1, n - 1):
    if a[i] == a[i-1] + 1:
        cur_len += 1
        max_len = max(max_len, cur_len)
    else:
        cur_len = 1

print(max_len)

算法及复杂度

  • 算法:一次遍历
  • 时间复杂度: O ( n ) \mathcal{O}(n) O(n) - 只需要遍历一次数组
  • 空间复杂度: O ( n ) \mathcal{O}(n) O(n) - 需要存储输入数组

题目链接

题目链接

小红的蛋糕切割

题目描述

小红拿到了一个矩形的蛋糕,共分成了 n n n m m m 列,共 n × m n \times m n×m 个区域,每个区域是一个小正方形,已知蛋糕每个区域都有一个美味度。

小红希望切割出一个正方形的小蛋糕(正方形边长必须平行于矩阵的边长,且必须都是完整的区域),自己吃掉正方形的部分,把剩下的部分给小紫吃。

小红希望两人吃的部分的美味度之和尽可能接近,小红吃的蛋糕美味度之和为 x x x,小紫吃的蛋糕美味度之和为 y y y,请你输出 ∣ x − y ∣ |x-y| xy 的最小值。

输入:

  • 第一行输入两个正整数 n n n m m m,代表蛋糕区域的行数和列数
  • 接下来 n n n 行,每行输入 m m m 个正整数,表示每个区域的美味度

输出:

  • 一个整数,代表 ∣ x − y ∣ |x-y| xy 的最小值

解题思路

这是一个枚举问题,可以通过以下步骤解决:

  1. 预处理:

    • 计算整个蛋糕的总美味度 total
    • 使用二维前缀和数组加速区域和的计算
  2. 枚举策略:

    • 枚举正方形的边长 len(从1到min(n,m))
    • 枚举正方形左上角的位置 (i,j)
    • 计算正方形区域的美味度和剩余区域的美味度
    • 更新最小差值
  3. 具体步骤:

    • 构建二维前缀和数组
    • 对每个可能的正方形大小和位置:
      • 计算正方形区域的美味度和
      • 计算剩余区域的美味度和
      • 计算两者差值的绝对值
      • 维护最小差值

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n, m;
    cin >> n >> m;
    
    // 构建二维前缀和数组
    vector<vector<ll>> sum(n + 1, vector<ll>(m + 1, 0));
    ll total = 0;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            int x;
            cin >> x;
            total += x;
            sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + x;
        }
    }
    
    // 计算区域和的函数
    auto getSum = [&](int x1, int y1, int x2, int y2) -> ll {
        return sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1];
    };
    
    ll ans = total;
    // 枚举正方形边长
    for(int len = 1; len <= min(n, m); len++) {
        // 枚举左上角位置
        for(int i = 1; i + len - 1 <= n; i++) {
            for(int j = 1; j + len - 1 <= m; j++) {
                ll square = getSum(i, j, i + len - 1, j + len - 1);
                ll remain = total - square;
                ans = min(ans, abs(square - remain));
            }
        }
    }
    
    cout << ans << endl;
    return 0;
}
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        
        // 构建二维前缀和数组
        long[][] sum = new long[n + 1][m + 1];
        long total = 0;
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                int x = sc.nextInt();
                total += x;
                sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + x;
            }
        }
        
        long ans = total;
        // 枚举正方形边长
        for(int len = 1; len <= Math.min(n, m); len++) {
            // 枚举左上角位置
            for(int i = 1; i + len - 1 <= n; i++) {
                for(int j = 1; j + len - 1 <= m; j++) {
                    int x1 = i, y1 = j;
                    int x2 = i + len - 1, y2 = j + len - 1;
                    long square = sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1];
                    long remain = total - square;
                    ans = Math.min(ans, Math.abs(square - remain));
                }
            }
        }
        
        System.out.println(ans);
    }
}
import sys
input=sys.stdin.readline

n, m = map(int, input().split())

# 构建二维前缀和数组
sum = [[0] * (m + 1) for _ in range(n + 1)]
total = 0
for i in range(1, n + 1):
    row = list(map(int, input().split()))
    for j in range(1, m + 1):
        total += row[j-1]
        sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + row[j-1]

def get_sum(x1, y1, x2, y2):
    return sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1]

ans = total
# 枚举正方形边长
for length in range(1, min(n, m) + 1):
    # 枚举左上角位置
    for i in range(1, n - length + 2):
        for j in range(1, m - length + 2):
            square = get_sum(i, j, i + length - 1, j + length - 1)
            remain = total - square
            ans = min(ans, abs(square - remain))

print(ans)

算法及复杂度

  • 算法:二维前缀和 + 枚举
  • 时间复杂度: O ( n 3 ) \mathcal{O}(n^3) O(n3) - 需要枚举正方形的大小和位置
  • 空间复杂度: O ( n ⋅ m ) \mathcal{O}(n \cdot m) O(nm) - 需要存储二维前缀和数组
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值