笔试题总结-编程题

Posted 水澹澹兮生烟.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了笔试题总结-编程题相关的知识,希望对你有一定的参考价值。

题目都是自己的思路,也有借鉴了别人然后自己写出的,这里我会写上自己的思路以及在写代码上的错误与最后改正的完整代码(C++代码)。题目大多来自牛客和LeetCode。在这里会附上链接。 

1.组队竞赛

分析题目:为了是队伍水平最大,也就是要求每个队伍的第二大水平尽可能为整体值的次最大值.本题的主要思路是贪心算法,贪心算法其实很简单,就是每次选值时都选当前能看到的局部最优解。所以这里的贪心就是保证每组的第二个值取到能选择的最大值就可以,我们每次尽量取最大,但是最大的数不可能是中位数,所以退而求其次,求每组中的第二大值。


#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
    long long n;
    long long sum = 0;
    vector<long long> ns;
    cin>>n;
    ns.reserve(n*3);
    for(size_t i = 0; i < n*3 ; i++){
        int a ;
        cin>> a;
        ns.push_back(a);//进行尾插
    }
    //对数组进行排序
    sort(ns.begin(),ns.end());
    int left = -1;
    int right = n*3;  
    while(right - left != 1){
        left++;
        right -= 2;
        sum += ns[right];
    }
    cout<<sum;
}

2.删除公共字符串

在解体的过程中我们如果使用暴力查找法会十分麻烦,效率太低。然后利用哈希表统计要删除的字符,将相容的字符用erase()删除掉。

#include<iostream>
#include<string>
using namespace std;
int main(){
    string str1;
    string str2;
    getline(cin,str1);
    getline(cin,str2);
    
    int hasht[256] = {0};
    //使用hash映射思想,将str2字符串中字符的个数映射到hash表当中
    //因此表中就统计了我们不用该出现的字符,即当他的值时大于0的时候,就不应该出现
    for(size_t i = 0; i < str2.size(); i++){
        hasht[str2[i]]++;
    }
    
    //我们直接将得到的新的字符串
    string newstring;
    for(size_t i = 0;i < str1.size(); i++){
        //此时对str1与hasht表中进行对比
        // 如果等于0,那么说明此时没有重复
        if(hasht[str1[i]] == 0){
            newstring += str1[i]; 
        }
    }
    cout << newstring << endl;
    return 0;
}

3.排序子序列

在这里要求的是排序子序列,那么排序序列就是非递增或者非递减。那么我们就可以分为三种情况进行考虑。

#include <iostream>
#include <vector>
using namespace std;
int main(){
    int n;
    cin>>n;
    int count = 0;
    vector<int> sn;
    //在这里,因为我们要比较的是sn[i]与sn[i+1]
    //所以此时我们必须给出n+1个数值,这样在访问是才不会是数组越界
    sn.resize(n+1);
    //给数组中传值
    for(size_t i = 0; i < n; i++){
        cin >> sn[i];
    }
    //在这里给出我们刚刚对给出的空间sn[n]的值为0
    sn[n] = 0;
    //开始进行比较
    int i = 0;
    while( i < n ){
        //判断是否为增排序
        if(sn[i] < sn[i+1]){
            while(i < n && sn[i] <= sn[i+1]){
                //当i小于n时且sn[i]大于sn[i+1],那么i++
                i++;
            }
            //如果不满足while循环条件,那么就有两种可能,要么就是访问到了末尾,要么就是从增变减
            count++;
            i++;
        }else if(sn[i] == sn[i+1]){
            //当其两个相等时,直接进行++操作
            i++;
        }else{
            while(i < n && sn[i] >= sn[i+1]){
                i++;
            }
            count++;
            i++;
        }
    }
    cout << count << endl;
    return 0;
}

4.倒置字符串

解这道题很简单,先将整个字符串逆转,再将单词进行逆转。

//整体的解题思路很简单,先将字符串整体逆置,再找到单词将他逆置
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main(){
    string str1;
    getline(cin,str1);
    //得到逆置字符串
   reverse(str1.begin(),str1.end());
    auto it = str1.begin();
    while(it != str1.end()){
        auto rit = it;
        while(rit !=str1.end() && *rit != ' '){
            rit++;
        }
        reverse(it, rit);
        if(rit != str1.end()){
            it = rit+1;
        }else{
            it = rit;
        }
    }
    cout<<str1<<endl;
}

5.字符串中找出连续最长的数字串

依旧使用贪心算法思想。我们先进行标记初始位置与数字串的个数,然后遍历字符串,在遍历时记录临时的数字串的个数与之前所标记的最大数字串的个数进行比较,最后得到最长的数字串。

#include<iostream>
#include<string>
using namespace std;
int main(){
    string str;
    int pos = 0;
    int count = 0;
    cin>>str;
    for(size_t i = 0; i < str.size() ;){
        int count_dex = 0;
        int pos_dex = 0;
        while(i < str.size()&&(str[i]>='0' && str[i]<='9')){
            count_dex++;
            pos_dex = i - count_dex + 1;//此时的位置就是i-count_dex+1
            i++;
        }
        if(count_dex > count){
            pos = pos_dex;
            count = count_dex;
        }
        i++;
    }
    string ss1 = str.substr(pos+1,count);
    cout<<ss1<<endl;
}

6.数组中出现次数超过一半的数字

分析:map进行存值,找出最多的数字,如长度大于一半,则直接返回

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        //我们先定义一个数组,下标用来标记值,数组内容用来标记数字的长度
        int nums[10000] = {0};
        //将numbers中的数字进行统计
        for(size_t i = 0 ; i < numbers.size(); i++){
            nums[numbers[i]]++;
        }
        //统计结束后,判断nums中那个下标对应的数值大于它的长度
        size_t i = 0;
        while(nums[i] <= numbers.size()/2){
            //当它小于一半时,继续循环
            i++;
        }
        return i;
    }
};

7.统计回文

直接使用暴力查找法。

#include<iostream>
#include<string>
using namespace std;
bool judge(string str){
    int left = 0;
    int right = str.size() - 1;
    while(left < right){
        if(str[left] == str[right]){
             left++;
            right--;
        }else
            return false;
    }
    return true;
}
int main(){
    string str1;
    getline(cin ,str1);
    string str2;
    getline(cin,str2);
    int count = 0;
    //使用暴力求解法
    for(size_t i = 0; i <= str1.size(); ++i){
        string str = str1;
        str.insert(i, str2);
        if(judge(str)){
            //如是回文,则进行++
            count++;
        }
    }
    cout << count << endl;
    return 0;
}

8.连续最大和 

动态求解,此时分为三种情况:

  • 1.当数组在进行向后加法操作时,一直是增加的;
  • 2.当数组中出现负数开始减少,但是此时整体的值是大于等于0的;
  • 3.当数组前n项之和开始小于0;
#include<iostream>
#include<vector>
using namespace std;
int main(){
    int a;
    while(cin>>a){
        vector<int> sn;
        for(int i = 0; i < a; i++){//对数组进行赋值
            int b;
            cin>>b;
            sn.push_back(b);
        }//开始对数组的子序列求和
        int max = sn[0];
        int mdex = 0;
        for(int i = 0; i < a; i++){
         if(mdex <= mdex+sn[i]){//当数组在加的时候是增长的
             mdex += sn[i];
             if(mdex > max){//并且此时判断是否大于之前的最大值,如果大于max,那么将其赋值给max
                 max = mdex;
              }
         }else{
             mdex += sn[i];
             if(mdex < 0 ){//如果此时的mdex小于0,那么说明再往后加的活会减少后面的值,因此,直接将mdex再次赋值为0
                 mdex = 0;
             }
         }
      }
        cout << max <<endl;
   }
}

9.最长公共子序列

这个题当要理解什么是最长公共子序列。利用动态规划求解。建立一个二位数组,对其进行标记,如下图:

if(A == B) sn[i][j] = sn[i-1][j-1] + 1;

else sn[i][j] = Max(sn[i][j-1] ,sn[i-1][j]);

#include<iostream>
#include<vector>
#include<string>
using namespace std;
int Max(int a ,int b){
    if(a > b)
        return a;
    return b;
}
int main(){
    string str1;
    string str2;
    while(cin>>str1>>str2){
        //定义一个二维数组,用来进行标记公共子序列
        vector<vector<int>> sn(str1.size()+1,vector<int>(str2.size()+1,0));
       size_t i = 0;
       size_t j = 0;
       for(i = 0; i < str1.size(); i++){
           for(j = 0; j < str2.size(); j++){
                if(str1[i] == str2[j]){
                    sn[i+1][j+1] = sn[i][j] + 1;
                    
                }else{
                    sn[i+1][j+1] = Max(sn[i+1][j],sn[i][j+1]);
                }
           }
       }
       cout<<sn[i][j]<<endl;
    }
    return 0;
}

10.合并区间

这个题我在刚开始解的时候总是在条件上判断出错。

思路:在这里我们先定义一个数组sar用来记录更新的合并区间,在定义一个ar来记录最后的所有合并好的区间,然后遍历二维数组,找到该合并的区间用sar来进行标记,当遍历到了不能合并的值时,将sar插入ar中,在对sar进行更新。跳出循环后,因为在上上面的循环中会少一次将sar进行push,因此在填上一次。

class Solution {
public:
static bool aws(vector<int> a, vector<int> b){
    return a[0] < b[0];
}
int max(int a ,int b){
    if(a > b) return a;
    return b;
}
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        vector<vector<int>> ar;
        int size = intervals.size();
        if(intervals.size() <= 1){
            return intervals;
        }
        sort(intervals.begin(),intervals.end(),aws);
         vector<int> sar = {intervals[0][0],intervals[0][1]};
        for(size_t i = 0; i < size; i++){
            if(sar[1] >= intervals[i][0]){//判断此时的值是否大于第二个值
            //大于,则判断是否需要更新sar的值
            if(sar[1] < intervals[i][1]) sar[1] = intervals[i][1];
            }
            if(sar[1] < intervals[i][0]){
                ar.push_back(sar);
                sar[0] = intervals[i][0];
                sar[1] = intervals[i][1];
            }
        }
        //上面循环少插入一次sar
        ar.push_back(sar);
        return ar;
    }
};

11.删除有序数组中重复的元素 ii

他的限制条件就是如果有两次或者两次以上,那就必须记成两次,减少删除的数字。

class Solution {
public:
    int removeDuplicates(int A[], int n) {
       if(n <= 2) return n;
        int count = 2;//因为题目说明最多只出现两次,因此用count进行标明
        for(int i = 2 ; i < n ; i++){
            if(A[count - 2] != A[i]){
                //此时两个数不相等,则将i位置的数值赋值给count
                A[count] = A[i];//避免了两次以上的重复
                count++;
             }
        }
        return count;
    }
};

12. 移除重复节点

久违的链表,就是是由哈希散列与前后指针解题。

class Solution {
public:
    ListNode* removeDuplicateNodes(ListNode* head) {
        if(NULL== head || NULL == head->next) return head;
        //利用hash表存储遍历过的节点
        int hashm[20001] = {0};
        hashm[head->val] = 1;//开始对第一个节点的值进行标记
        ListNode *pre = head, *p = head->next;
        while(p){//当p不为空
            if(hashm[p->val] == 0){
                //说明此时p指向的val是第一次出现,然后将hash表中标记的pre对应得值进行标记
                hashm[p->val] = 1;//标记之后,后面再遇到就可以直接将他删除
                pre = p;
                p =p->next;//将两个指针向后移动
            }else{
                //如果此时的hashm中对应的值补位0,则说明已经出现过了,那么直接对其进行删除
                pre->next = p->next;
                p = p->next;
            }
        }
        return head;
    }
};

 13.

以上是关于笔试题总结-编程题的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript笔试题(js高级代码片段)

字节笔试题(含答案)

百度笔试题面试题总结1

Day03:笔试题总结

Day03:笔试题总结

剑指Offer——当当+搜狐+好未来笔试题+知识点总结