C++面试宝典笔试题记录

链表相关的题

  • 删除单向链表中的某个节点
struct listNode{
    int key;
    listNode* next;
};
listNode* deleteNode(listNode* head, int target)
{
    listNode* node1 = head;
    listNode* node2 = NULL;
    if (node1->key == target)  // 先判断是否删除头节点
    {
        head = head->next;
        free(node1);
        node1 = NULL;
        return head;
    }
    else
    {
        while (node1 != NULL)
        {
            node2 = node1;
            node1 = node1->next;
            if (node1->key != target)
                continue;
            else
            {
                node2->next = node1->next;
                free(node1);
                node1 = NULL;
                break;
            }
        }
        return head;
    }
}
  • 对链表进行排序
    方法:每轮找出最小的数放在当前排序序列的最前面,类似于选择排序,但是交换次数比选择排序多,跟冒泡排序的次数相当。
void listSort(listNode* head)
{
    if (head == NULL || head->next == NULL)
        return;
    listNode* p = head;
    listNode* q = p->next;
    int tmp;
    while (p->next!=NULL)
    {
        while (q!=NULL)
        {
            if (p->key > q->key)
            {
                tmp = p->key;
                p->key = q-key;
                q-key = tmp;
            }
            q = q->next;
        }
        p = p->next;
    }
    return head;
}

使用冒泡排序算法:

void listBubbleSort(listNode* head)
{
    if (head == NULL || head->next == NULL)
        return;
    listNode* cur = head;
    listNode* tail = NULL;
    int tmp;
    while (cur != tail)
    {
        while (cur->next != tail)  // 内循环,每次将最大的数放
                                   // 在本次排序的序列后面
        {
            if (cur->key > cur->next->key)
            {
                tmp = cur->key;
                cur->key = cur->next->key;
                cur->next->key = tmp;
            }
        }
        tail = cur;  // 将tail放在已排好序的最大数的前面一个位置
        cur = head;  // 继续下一轮排序
    }
    return ;
}

参考博客:
http://blog.csdn.net/bitboss/article/details/51602826

  • 链表反转
listNode* listRevert(listNode* head)
{
    if (head == NULL || head->next == NULL)
        return ;
    listNode* p = head;
    listNode* q = p->next;
    listNode* r = NULL;
    p-next = NULL;
    while (q)
    {
        r = q->next;
        q->next = p;
        p = q;
        q = r;
    }
    head = p;
    return head;
}
  • 将两个升序排序的链表合并成一个升序排序的链表
// 使用非递归实现
listNode* Merge(listNode* head1, listNode2* head2)
{
    // 先考虑存在空链表的情况
    if (head1 == NULL)
        return head2;
    if (head2 == NULL)
        return head1;
    listNode* head = NULL;
    listNode* tmp = head;
    // 先找出新链表的表头
    if (head1->key <= head2->key)
    {
        head = head1;
        head1 = head1->next;
    }
    else
    {
        head = head2;
        head2 = head2->next;
    }
    // 找到表头后移动tmp指针,注意,若移动head会使tmp同时移动,最后会找不到链表的头节点,这就是为什么要定义两个指针。
    while (head1!=NULL&&head2!=NULL)
    {
        if (head1->key <= head2->key)
        {
            tmp->next = head1;
            tmp = head1;
            head1 = head1->next;
        }
        else 
        {
            tmp->next = head2;
            tmp = head2;
            head2 = head2->next;
        }
    }
    if (head1!=NULL)
        tmp->next = head1;
    if (head2!=NULL)
        tmp->next = head2;
    return head;
}

// 使用递归实现
listNode* Merge2(listNode* head1, listNode* head2)
{
    // 退出条件
    if (head1 == NULL)
        return head2;
    if (head2 == NULL)
        return head1;
    listNode* head = NULL;
    if (head1->key <= head2->key)
    {
        head = head1;
        head->next = Merge2(head1->next, head2);
    }
    else 
    {
        head = head2;
        head->next = Merge2(head1, head2->next);
    }
    return head;
}

注意:对于函数的返回值,不能返回栈里的元素,也就是局部变量(函数体内定义的变量),可返回由malloc或new在堆里生成的变量,或者如上返回一个临时指针,但是该指针指向的是外部已有的一个空间,因此可以这么使用。但如果指向的是一块临时分配的栈,则不能返回该临时变量。

凑硬币

给定1分,2分,5分的硬币,问凑成1元的方案有多少种?

  • 使用for循环实现
// 凑硬币
void Coin(const int n, int money[])
{
    int count = 0;
    for (int n1 = n/money[0]; n1>=0;n1--)
    {
        for (int n2 = (n- money[0]*n1)/2; n2>=0; n2--)
        {
            cout << "5分:" << n1 << "个  " << "2分:" << n2 << "个  " << "1分:" << (n-n1*money[0]-n2*money[1]) << endl;
            count++;
        }
    }
    cout << "共" << count << "种组合。" << endl;
}
  • 使用递归实现
这里写代码片

奶牛生子问题

一只刚出生的奶牛,4年生1只奶牛,以后每一年生1只。现在给你一只刚出生的奶牛,求20年后有多少奶牛。

// 奶牛生子问题
int calCowNum(const int year)
{
    int i = 0;
    int sumCow = 1;
    for (i = 1; i <= year; i++)  // 表示第一只奶牛从第一年到第二十年生子的情况
    {
        if (i>=4)
        {
            if (year-i>3)  // 如果当前生的奶牛是在第16年以内生的
                sumCow += calCowNum(year - i); // 表示第一只奶牛生的奶牛,假设命名为Alice,加上Alice生的奶牛
            else
                sumCow++;  // 第17年以后生的奶牛在第20年以内不会生小奶牛
        }
    }
    return sumCow;
}

字符串处理问题

  • 字符串循环移位
    编写一个函数,把一个char组成的字符串循环右移n位。例如,原来是“abcdefghi”,如果n=2,移位后应该是“hiabcdefg”。
    备注:本题主要考察标准库函数的熟练程度,常用的有strcpy, memcpy, memset。
void LoopMove(char *pStr, int steps)
{
    int n = strlen(pStr) - steps;
    char tmp[MAX_STR_LEN];
    strcpy(tmp, pStr+n);  
    strcpy(tmp+steps, pStr);
    tmp[strlen(pStr)] = '\0';
    strcpy(pStr, tmp);
}
  • String类的实现
    编写类String的构造函数、析构函数和赋值函数。
class String
{
public:
    String(const char *str = NULL);    // 普通构造函数
    String(const String &other);       // 拷贝构造函数
    ~String(void);     // 析构函数
    String & operate =(const String &other);                 // 赋值函数
private:
    char *m_data;   // 用于保存字符串
};

inline String::String(const char *str = NULL)    // 普通构造函数
{
    if (str == NULL)  // 若为空,则将m_data置为默认值
    {
        m_data = new char[1];
        *m_data = '\0';
    }
    else
    {
        m_data = new char[strlen(str)+1];  // 注意这里不能用sizeof, 使用sizeof会得到指针的大小而不是数组的大小。
        strcpy(m_data, str);
    }
}

inline String::String(const String &other)      // 拷贝构造函数
{
    m_data = new char[strlen(other.m_data)+1];  //在类的成员函数内可以访问同种对象的私有成员(同种类肯定是友元关系) 
    strcpy(m_data, other.m_data);
}

inline String::~String(void)    // 析构函数
{
    delete [] m_data;
}

inline String::String & operate =(const String &other)     // 赋值函数
{
    if (this == other)
        return *this;
    delete [] m_data;
    m_data = new char[strlen(other.data)+1];
    strcpy(m_data, other.m_data);
    return *this;
}

树遍历问题

  • 二叉树深度优先遍历解决最大和的问题

有n*n个格子,每个格子里有正数或者0,从最左上角望最右下角走,只能向下和向右,把所有经过的格子的数加起来,求最大值SUM。
DP算法,将问题分解成子问题,求局部最优解,计算从a[0][0]到a[n-1][n-1]的最大和问题,即为求a[0][1]和a[1][0]到a[n-1][n-1]的最大的和的问题。代码如下:

#include <iostream>
using namespace std;
const int N = 4;

// 二维数组形参还可以为int arr[][N]或者int (*arr)[N];
// 这里行数可以不说明,但是列数必须说明,因为如果省略了第二维或者更高维的大小,编译器将不知道如何正确的寻址。
int MaxSum(int arr[N][N], int row, int col)
{
    if (row == N || col == N)
        return 0;
    // 这里分解成两个子问题求解
    int temp1 = MaxSum(arr, row+1, col) + arr[row][col];
    int temp2 = MaxSum(arr, row, col+1) + arr[row][col];
    // 返回两个子问题中的最大和
    return temp1 > temp2 ? temp1 : temp2;
}

int main()
{
    int arr[4][4] = {{0,0,0,4},{0,3,0,0},{5,0,0,9},{0,0,2,1}};
    cout << MaxSum(arr, 0, 0);
    return 0;
}

> 上题,如何增加hash表来保存中间结果,避免重复递归还未写。

返回无序数组排序后的最大差值

请设计一个复杂度为O(n)的算法,计算一个未排序数组中排序后相邻元素的最大差值。给定一个数组的大小n和整数数组A,请返回最大差值。保证数组元素个数大于等于2,小于等于500。

输入示例:
4
9 3 1 10
输出示例:
6

要求时间复杂度为O(n),则不能直接进行排序来做。


  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值