校招算法笔面试 | 校招笔面试真题-小Q的排序

题目## 题目

题目链接

解题思路

  1. 题目要求:

    • 有两种操作:
      1. 将前 n − 1 n-1 n1 个数排为升序
      2. 将后 n − 1 n-1 n1 个数排为升序
    • 求最少需要多少次操作使序列变为升序
  2. 分析不同情况:

    • 如果序列已经是升序,需要0次操作
    • 如果最小值在开头或最大值在结尾,需要1次操作
    • 如果最小值在结尾且最大值在开头,需要3次操作
    • 其他情况需要2次操作

代码

#include <iostream>
#include <vector>
using namespace std;

int minOperations(int n, vector<int>& arr) {
    // 检查是否已经是升序
    bool isSorted = true;
    int minVal = arr[0], maxVal = arr[0];
    
    for(int i = 1; i < n; i++) {
        if(arr[i] < arr[i-1]) {
            isSorted = false;
        }
        minVal = min(minVal, arr[i]);
        maxVal = max(maxVal, arr[i]);
    }
    
    if(isSorted) return 0;
    if(minVal == arr[0] || maxVal == arr[n-1]) return 1;
    if(minVal == arr[n-1] && maxVal == arr[0]) return 3;
    return 2;
}

int main() {
    int n;
    cin >> n;
    vector<int> arr(n);
    for(int i = 0; i < n; i++) {
        cin >> arr[i];
    }
    cout << minOperations(n, arr) << endl;
    return 0;
}
import java.util.*;

public class Main {
    static int minOperations(int n, int[] arr) {
        // 检查是否已经是升序
        boolean isSorted = true;
        int minVal = arr[0], maxVal = arr[0];
        
        for(int i = 1; i < n; i++) {
            if(arr[i] < arr[i-1]) {
                isSorted = false;
            }
            minVal = Math.min(minVal, arr[i]);
            maxVal = Math.max(maxVal, arr[i]);
        }
        
        if(isSorted) return 0;
        if(minVal == arr[0] || maxVal == arr[n-1]) return 1;
        if(minVal == arr[n-1] && maxVal == arr[0]) return 3;
        return 2;
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] arr = new int[n];
        for(int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
        }
        System.out.println(minOperations(n, arr));
    }
}
def min_operations(n, arr):
    # 检查是否已经是升序
    is_sorted = True
    min_val = max_val = arr[0]
    
    for i in range(1, n):
        if arr[i] < arr[i-1]:
            is_sorted = False
        min_val = min(min_val, arr[i])
        max_val = max(max_val, arr[i])
    
    if is_sorted:
        return 0
    if min_val == arr[0] or max_val == arr[n-1]:
        return 1
    if min_val == arr[n-1] and max_val == arr[0]:
        return 3
    return 2

n = int(input())
arr = list(map(int, input().split()))
print(min_operations(n, arr))

算法及复杂度

  • 算法:贪心
  • 时间复杂度: O ( n ) \mathcal{O}(n) O(n) - 只需要遍历一次数组
  • 空间复杂度: O ( 1 ) \mathcal{O}(1) O(1) - 只需要常数级别的额外空间

题目链接

解题思路

这是一个并查集问题。关键点如下:

  1. n n n 个人参加活动,每人有唯一编号 ( 0 ≤ i < n ) (0 \leq i < n) (0i<n)
  2. m m m 对人互相认识
  3. 通过认识的人可以认识新的人
  4. 需要计算小A最多能认识多少新朋友

解题思路:

  1. 使用并查集记录所有人的连通关系
  2. 记录小A已经直接认识的人
  3. 找到小A所在连通分量的大小
  4. 最终结果 = 连通分量大小 - 1(去掉自己) - 已认识的人数

代码

#include <iostream>
#include <vector>
#include <set>
using namespace std;

class UnionSet {
private:
    vector<int> parents;
    vector<int> rank;
    
public:
    UnionSet(int n) {
        parents.resize(n);
        rank.resize(n, 1);
        for (int i = 0; i < n; i++) {
            parents[i] = i;
        }
    }
    
    int find(int x) {
        if (parents[x] != x) {
            parents[x] = find(parents[x]);
        }
        return parents[x];
    }
    
    void union_set(int x, int y) {
        int px = find(x), py = find(y);
        if (px != py) {
            if (rank[px] > rank[py]) {
                parents[py] = px;
                rank[px] += rank[py];
            } else {
                parents[px] = py;
                rank[py] += rank[px];
            }
        }
    }
    
    int get_rank(int x) {
        return rank[find(x)];
    }
};

int main() {
    int n, A, m;
    cin >> n >> A >> m;
    
    UnionSet us(n);
    set<int> known;
    
    for (int i = 0; i < m; i++) {
        int x, y;
        scanf("%d,%d", &x, &y);
        if (x == A) known.insert(y);
        else if (y == A) known.insert(x);
        us.union_set(x, y);
    }
    
    cout << us.get_rank(A) - 1 - known.size() << endl;
    return 0;
}
import java.util.*;

public class Main {
    static class UnionSet {
        private int[] parents;
        private int[] rank;
        
        public UnionSet(int n) {
            parents = new int[n];
            rank = new int[n];
            for (int i = 0; i < n; i++) {
                parents[i] = i;
                rank[i] = 1;
            }
        }
        
        public int find(int x) {
            if (parents[x] != x) {
                parents[x] = find(parents[x]);
            }
            return parents[x];
        }
        
        public void union(int x, int y) {
            int px = find(x), py = find(y);
            if (px != py) {
                if (rank[px] > rank[py]) {
                    parents[py] = px;
                    rank[px] += rank[py];
                } else {
                    parents[px] = py;
                    rank[py] += rank[px];
                }
            }
        }
        
        public int getRank(int x) {
            return rank[find(x)];
        }
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int A = sc.nextInt();
        int m = sc.nextInt();
        sc.nextLine();
        
        UnionSet us = new UnionSet(n);
        Set<Integer> known = new HashSet<>();
        
        for (int i = 0; i < m; i++) {
            String[] line = sc.nextLine().split(",");
            int x = Integer.parseInt(line[0]);
            int y = Integer.parseInt(line[1]);
            if (x == A) known.add(y);
            else if (y == A) known.add(x);
            us.union(x, y);
        }
        
        System.out.println(us.getRank(A) - 1 - known.size());
    }
}
class UnionSet:
    def __init__(self, n):
        self.parents = [i for i in range(n)]
        self.rank = [1] * n
        
    def find(self, x):
        if self.parents[x] != x:
            self.parents[x] = self.find(self.parents[x])
        return self.parents[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px != py:
            if self.rank[px] > self.rank[py]:
                self.parents[py] = px
                self.rank[px] += self.rank[py]
            else:
                self.parents[px] = py
                self.rank[py] += self.rank[px]

n = int(input())
A = int(input())
m = int(input())

us = UnionSet(n)
known = set()

for _ in range(m):
    x, y = map(int, input().split(','))
    if x == A:
        known.add(y)
    elif y == A:
        known.add(x)
    us.union(x, y)

root = us.find(A)
total = sum(1 for i in range(n) if us.find(i) == root)
print(total - 1 - len(known))

算法及复杂度

  • 算法:并查集
  • 时间复杂度: O ( m α ( n ) ) \mathcal{O}(m\alpha(n)) O(mα(n)) - m m m 为边数, α ( n ) \alpha(n) α(n) 为阿克曼函数的反函数,近似为常数
  • 空间复杂度: O ( n ) \mathcal{O}(n) O(n) - 需要存储并查集的父节点数组和秩数组
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值