• [专业课] 真题 程序题


    2015年真题代码
    1. 求马鞍点

    思路:创建ma和mi数组分别存储最大最小值,其中,ma[ i ] = j 表示第 i 行的最大值在第 j 列。最后遍历一遍max数组。假设没有重复的数字。

    const int N = 1000;
    int a[N][N];
    int n, m, max, min;
    int ma[N], mi[N];
    int main() {
        scanf("%d %d", &n, &m); //n行m列
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < m; j++) {
                scanf("%d", &a[i][j]);
            }
        }
        // 找行最大
        for(int i = 0; i < n; i++) {
            int maxIndex = -0x3f;
            for(int j = 0; j < m; j++) {
                if(a[i][j] > maxIndex) {
                    maxIndex = a[i][j];
                    ma[i] = j; // 第i行的最大值下标为j
                }
            }
        }
        
        // 找列最小
        for(int i = 0; i < m; i++) { //第i列第j行
            int minIndex = 0x3f;
            for(int j = 0; j < n; j++) {
                if(a[j][i] < minIndex) {
                    minIndex = a[j][i];
                    mi[i] = j; // 第i列的最小值下标为j
                }
            }
        }
        
        for(int i = 0 ;i < n; i++) {
            int k = ma[i]; //k存储的是第i行最大值的列数
            if (mi[k] == i) cout << i << " " << k;
        }
        return 0;
    }
    
    2. 类三路归并

    题目:设计一个算法,给出一个有序列,按模3余0 余1 余2排序。

    // 我写的是无序序列,在三路划分后进行快速排序
    void quickSort(int l, int r) {
        if (l > r) return;
        int i = l, j = r ,temp = a[l];
        while(i < j) {
            while(i < j && a[j] > temp) j--;
            if(i < j) { a[i] = a[j]; i++; }
            while(i < j && a[i] < temp) i++;
            if(i < j) { a[j] = a[i]; j--; }
        }
        a[i] = temp;
        quickSort(l, i - 1);
        quickSort(i + 1, r);
    }
    
    int main() {
        scanf("%d", &n);
        for(int i = 0; i < n; i++) {
            scanf("%d", &a[i]);
        }
        int i = 0, j = 0, k = n - 1;
        while(j <= k) {
            int temp = a[j] % 3;
            if (temp == 0) swap(a[i++], a[j++]);
            else if(temp == 1 ) j++;
            else swap(a[j], a[k--]);
        }
    //    cout << a[0] << " " << a[i-1];
        quickSort(0, i-1);
        quickSort(i, k-1);
        quickSort(k, n-1);
        for(int i = 0; i < n; i++) {
            cout << a[i] << " ";
        }
    }
    
    2016年真题代码
    1. 数组无序,实现输出一个有序单循环链表。

    (在没有其他思路的情况下硬解是最直接的)

    2. 找出某个结点的所有祖先结点。(中序+深搜)
    3. 集群环境中为不同运行时间的计算机分配相同的任务,使得总消耗时间最短。
    int n, m, ans, idx, t[N];
    int f[N]; //f数组存储每台机器已耗费的时间
    int main() {
        scanf("%d %d", &n, &m); //n个任务m台机器
        for(int i = 1; i <= m; i++) {
            scanf("%d", &t[i]); //输入每台机器处理该任务需要耗费的时间
        }
        for(int i = 1;i <= n; i++) {
            int cur = 2e9;
            idx = 0; // 第i个任务加入index机器中 且耗费的时间为min
            for(int j = 1; j <= m; j++) {
                if( cur > f[j] + t[j]) {
                    cur = f[j] + t[j];
                    idx = j; // 更新cur值且更新下标
                }
            }
            f[idx] += t[idx]; // 更新所用时间
        }
        cout << f[idx];
        return 0; //最后保存的idx就是最后的时长
    }
    
    2017年真题代码
    1. 二进制数中1的个数
    // 此时的时间复杂度只与1有关
    int countOne2(int num) {
        int count = 0;
        while(num > 0) {
            // 原理: 每次取出最后一位和1做逻辑与操作
            if((num & 1) == 1) count++;
            num>>=1; // num = (num >> 1);
        }
        return count;
    }
    // 时间复杂度为O(logn)
    int countOne1(int num) {
        int c = 0;
        while(num > 0) {
            if(num % 2 == 1) c++;
            num = num / 2;
        }
        return c;
    }
    /*
     O(1) 把a做单位数过滤,默认32位,int型
     */
    int countOne3(int num) {
        int m_1  = 0x55555555; // 0101 8对
        int m_2  = 0x33333333;  // 0011 8对
        int m_4  = 0x0f0f0f0f; // 00001111 4对
        int m_8  = 0x00ff00ff;
        int m_16 = 0x0000ffff;
        
        int b = (num & m_1) + ((num >> 1) & m_1);
        int c = (b & m_2) + ((b >> 2) & m_2);
        int d = (c & m_4) + ((c >> 4) & m_4);
        int e = (d & m_8) + ((d >> 8) & m_8);
        int f = (e & m_16) + ((e >> 16) & m_16);
        return f;
    }
    
    2. 快排改进算法
    // 取中位数的快速排序 最坏情况下的时间复杂度为O(nlogn)
    void quickSortMidian(int a[], int left, int right) {
        int mid = left + ((right - left) >> 1);
        int temp = a[mid];
        int i = left, j = right;
        if(j <= i) return; //这个真是不能忘 不然它跳不出来 会越界的
        while(i < j) {
            while (i < j && a[i] < temp) i++;
            if(i < j) {
                swap(a[i], a[j]);
                j--;
            }
            while(i < j && a[j] > temp) j--;
            if(i < j) {
                swap(a[j], a[i]);
                i++;
            }
        }
        a[i] = temp;
        quickSortMidian(a, left, i - 1);
        quickSortMidian(a, i + 1, right);
    }
    
    int main() {
        scanf("%d", &n);
        for(int i = 0; i < n; i ++ ){
            scanf("%d", &a[i]);
        }
        quickSortMidian(a, 0, n-1);
    }
    
    // 3路划分
    void quick3way(int a[], int left, int right) {
        if(right <= left) return;
        int i = left, j = right, mid = left + 1;
        int x = a[left];
        while(mid <= j) {
            if(a[mid] < x) {
                swap(a[i], a[mid]);
                i++; mid++;
            } else if(a[mid] > x) {
                swap(a[j], a[mid]);
                j--;
                cout << endl;
            } else {
                mid ++;
            }
        } // 区域划分为了 a[i...i-1] < x = a[i .. j] < a[j+1 .. right]
        // i指向的是第一个等于x的位置 而j指向的是等于x的最后一个数
        quick3way(a, left, i - 1);
        quick3way(a, mid, right);
    }
    
    int main() {
        scanf("%d", &n);
        for(int i = 0; i < n; i ++ ){
            scanf("%d", &a[i]);
        }
        quick3way(a, 0, n-1);
    }
    
    3. M*N的方格中,确定a到b的最近距离
    typedef pair<int, int> PII;
    // 假设障碍物为1 通路为0
    const int N = 1000;
    int n, m, res; //n行m列
    int a[N][N], v[N][N], w[N][N];
    int st[2], de[2];
    int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}; //偏移量
    queue<PII> q;
    stack<PII> s;
    
    void bfs() {
        if (q.empty()) return; //队列为空时 返回
        // 如果是1的话表示为障碍
        // 如果是0的话表示为通路 进而判断是否已访问
        // 如果没访问过 则更新w 并且加入队列 如果访问过就不管了
        // 第一次遍历到b结点时停止
        while(!q.empty()) {
            int size = q.size(); //此时队列的长度
            for (int i = 0; i < size; i++) {
                PII p1 = q.front();
                q.pop();
                for(int k = 0; k < 4; k++) {
                    int x = p1.first + dx[k], y = p1.second + dy[k];
                    if(x >= 1 && x <= n && y >= 1 && y <= m && v[x][y] == -1 && a[x][y] == 0) {
                        v[x][y] = 0;
                        w[x][y] = w[p1.first][p1.second] + 1;
                        PII p2(x,y);
                        q.push(p2);
                    }
                    if (x == de[0] && y == de[1]) {
                        w[x][y] = res = w[p1.first][p1.second] + 1;
                        return;
                    }
                }
            }
        } 
    }
    void findroot(PII p, int root) {
        if(root == 1) {
            PII p1(st[0], st[1]);
            s.push(p1);
            return;
        }
        for(int k = 0; k < 4; k++) {
            int x = p.first + dx[k], y = p.second + dy[k];
            if(x >= 1 && x <= n && y >= 1 && y <= m && w[x][y] == root - 1) {
                PII p1(x,y);
                s.push(p1);
                findroot(p1, root - 1);
            }
        }
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                scanf("%d", &a[i][j]);
            }
        }
        memset(v, -1, sizeof v); // 结点均未访问
        scanf("%d%d", &st[0], &st[1]); //起点
        scanf("%d%d", &de[0], &de[1]); //目的地
        PII p1(st[0], st[1]);
        PII p2(de[0], de[1]);
        q.push(p1);
        bfs();
        findroot(p2, res);
        while (!s.empty()) {
            PII p = s.top(); s.pop();
            cout << "(" << p.first << "," << p.second << ") " << endl;
        }
        return 0;
    }
    
    2018年真题
    查找优化

    问题: 已知一个含有n个元素的数组,我们需要找到其中的最大值和最小值,假设存在着一种需要比较2n次的方法,请问是否存在更优的算法,如果存在请给出思路说明,不存在的话请说明理由。

    :存在把数组两两一堆分组,如果数组元素个数为奇数,就最后单独分一个,然后分别对每一组的两个数比较,把小的放在左边,大的放在右边,这样遍历下来,总共比较的次数是n/2次;在前面分组的基础上,可以得出结论,最小值一定在每一组的左边部分找,最大值一定在数组的右边部分找,最小值和最大值的查找分别需要比较n/2次和n/2次,这样就可以找到了,比较的次数为3n/2次。

    找英雄数

    解法:和找众数类似。对于当前元素,如果栈空,则入栈,如果栈不为空,则与栈顶元素进行比较,相等则入栈,反之则出栈栈顶元素,最后遍历一遍,count大于总个数的一半,返回正确结果。

    // 输入 9
    // 1 2 3 1 1 1 2 1 1
    int n, m, hero, ans;
    vector<int> a;
    int st[1024];
    void heroNumber() {
        int top = -1;
        for(int i = 0; i < a.size(); i++) {
            // 如果栈空或元素相等 元素直接入栈
            if(top == -1 || st[top] == a[i]) st[++top] = a[i];
            else top--; // 如果有不同的直接抵消 进行下一个元素判断
        }
        if(top == -1) cout << "error" << endl;
        else {
            for(int i = 0; i < a.size(); i++) {
                if(a[i] == st[top]) ++ans;
            }
            if (ans > (n / 2)) {
                cout << st[top];
            } else cout << "error" << endl;
        }
    }
    int main() {
        scanf("%d", &n);
        for(int i = 0; i < n; i++) {
            scanf("%d", &m);
            a.push_back(m);
        }
        heroNumber();
    }
    
    
    求出数组A和B的交集
    // 如果运算数小,可以使用位运算来做
    int n, m, max_a, max_b, ans;
    int a[N], b[N];
    
    int main() {
        scanf("%d %d", &n, &m);
        max_a = max_b = -10e9;
        for(int i = 1 ; i <= n; i++) {
            scanf("%d", &a[i]);
            max_a = (a[i] > max_a ? a[i] : max_a);
        }
        for(int i = 1 ; i <= m; i++) {
            scanf("%d", &b[i]);
            max_b = (b[i] > max_b ? b[i] : max_b);
        }
        int len = max(max_b, max_a);
        int sa[len], sb[len];
        memset(sa, 0, sizeof sa);
        memset(sb, 0, sizeof sb);
        for(int i = 1; i <= n; i++) {
            sa[a[i]] = 1;
        }
        for(int i = 1; i <= m; i++) {
            sb[b[i]] = 1;
        }
        for(int i = 1; i <= n; i++) {
            if (sa[a[i]] == sb[a[i]]) {
                cout << a[i];
                ans++;
            }
        }
        if(ans == 0) cout << "无" <<endl;
        return 0;
    }
    
    合并k重链表

    题目:合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

    时间复杂度: O(Nlog k ),其中k 是链表的数目。弹出操作时,比较操作的代价会被优化到 O(logk) 。同时,找到最小值节点的时间开销仅仅为O(1)。最后的链表中总共有 N个节点。空间复杂度:创造一个新链表的需要O(n)开销

    ListNode* mergeKLists(vector<ListNode*>& lists) {
      int len = lists.size();
      if(len == 0) return NULL;
      priority_queue<int, vector<int>, greater<int>> heap;
      // 构造小根堆
      ListNode *ans = new ListNode(0), *p = ans;
      for(int i = 0; i < len; i++) {
        ListNode *cur = lists[i];
        while(cur) {
          int x = cur->val;
          heap.push(x);
          cur = cur->next;
        }
      }
      while(heap.size() > 0) {
        int a = heap.top(); heap.pop();
        ListNode *cur = new ListNode(a); 
        //cout << "a's value is" << a->val;
        p->next = cur;
        p = p->next;
      }
      return ans->next;
    }
    
    求序列中所有和为m的子集

    题目:给定一个序列,设计算法求出元素和为M的所有子集合(让子集合里面的数据加起来刚好等于设定的值M)

    思想:类似于全排列问题,对于一个位置上有取或不取几种两种选择,对每个位置深搜+剪枝,打印路径即为所有子集数。

    int path[N], a[N];
    int n, m, idx;
    void fun(int k, int m) {
        if(k>=n) return;
        if (a[k] == m) {
            path[idx++] = a[k];
            for(int i = 0; i < idx; i++) {
                cout << path[i] << " ";
            }
            cout << endl;
            idx --; // 模拟的时候漏了这个
            fun(k+1, m);
        } else if(a[k] > m) {
             fun(k+1, m);
        } else {
            // 取当前位
            path[idx++] = a[k]; // 存路径
            fun(k + 1, m - a[k]);
            // 如果不取
            idx --; //恢复现场
            fun(k + 1, m);
        }
        
    }
    int main() {
        scanf("%d %d", &n, &m);
        for(int i = 0; i < n; i++) {
            scanf("%d", &a[i]);
        }
        fun(0, m);
        return 0;
    }
    
    
    2019年真题代码
    1. Prime算法

      #include <iostream>
      #include <vector>
      #include <queue>
      using namespace std;
      const int N = 20;
      int dis[N][N], vset[N], e[N]; //dis存储邻接矩阵,vset数组记录结点访问,e记录最短距离
      int n, m, sum;
      int a, b, w;
      int mins, idx;
      int minTree(int x) {
          vset[x] = 1;
          for(int i = 1; i <= n; i++) {
              if(i!=x && dis[x][i] < INT_MAX) {
                  e[i] = dis[x][i];
              } else e[i] = INT_MAX;
          }
          for(int i = 2; i <= n; i++) {
              mins = INT_MAX;
              for(int j = 1; j <= n; j++) {
                  if(vset[j] == 0 && e[j] < mins) {
                      mins = e[j];
                      idx = j;
                  }
              }
              sum += mins;
              vset[idx] = 1;
              cout << "mins is " << mins << endl;
              for(int j = 1; j <= n; j++) {
                  if(vset[j] == 0 && dis[idx][j] < e[j]) {
                      e[j] = dis[idx][j];
                  }
              }
          }
          return sum;
      }
      
      int main() {
          scanf("%d%d", &n, &m);
          memset(vset, 0, sizeof vset);
          for(int i = 1; i <= n; i++) {
              for(int j = 1; j <= n; j++) {
                  if(i!=j) dis[i][j] = INT_MAX;
                  else dis[i][j] = 0;
              }
          }
          while(m--) {
              scanf("%d%d%d", &a, &b, &w);
              dis[a][b] = dis[b][a] = w;
          }
          for(int i = 1; i <= n; i++) {
              for(int j = 1; j <= n; j++) {
                  cout << dis[i][j] << " ";
              }
              cout << endl;
          }
          // 从第一个岛屿开始
          minTree(1);
          cout << sum;
      }
      
      
    2. #include <vector>
      #include <queue>
      
      int n, k, res;
      int main() {
          //升序 greater
          priority_queue<int, vector<int>, greater<int>> heap;
          //降序 priority_queue <int,vector<int>,less<int> >q;
          scanf("%d", &n);
          for(int i = 0; i < n; i++) {
              scanf("%d", &k);
              heap.push(k); //建立小根堆
          }
          while(heap.size() > 1) {
              int a = heap.top(); heap.pop();
              int b = heap.top(); heap.pop();
              res += (a + b);
              heap.push(a+b);
          }
          cout << heap.top();
      }
      
  • 相关阅读:
    骨灰级程序员20条编程经验
    js常用正则表达式
    css样式大全(整理版)
    ASP.NET中常用的26个优化性能方法
    C# 中的委托和事件
    Page的ResolveClientUrl与ResolveUrl读取路径
    层设定固定高度,内容超过高度,自动延伸
    Catalan数(卡塔兰数)
    称球问题
    zabbix分布式监控系统安装配置
  • 原文地址:https://www.cnblogs.com/recoverableTi/p/12248070.html
Copyright © 2020-2023  润新知