考研复试机试 | 详细注释 | C++

1.两数之和

题目

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

提示:

2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案

C++代码

vector容器 见C++相关博客

vector<int> twoSum(vector<int>& nums, int target) {
	unordered_map<int, int> hashtable;
	for (int i = 0; i < nums.size(); i++)
	{
		// 在哈希表中找 target-num[i]
		// unordered_map<int,int>::iterator 可以用auto代替这一串冗长的代码
		auto it = hashtable.find(target - nums[i]);
		// 如果找到
		if (it != hashtable.end()) {
			// it->first指的是key,it->second指的是value
			return { it->second, i };
		}
		// 如果找不到
		hashtable[nums[i]] = i;
	}
	return {};
}

调试+调用

由于考研复试需要,无奈从Python转为C++,所有的代码操作都不熟悉,现将相关调试代码记录如下

int main() {
	vector<int> nums;
	vector<int> res;
	for (int i = 0; i < 4; i++)
	{
		int a;
		cin >> a;
		nums.push_back(a);
	}
	int target;
	cin >> target;
	//函数调用
	res = twoSum(nums, target);
	//遍历容器
	for (vector<int>::iterator it = res.begin(); it != res.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

2.两数相加

题目

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
在这里插入图片描述

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
示例 2:

输入:l1 = [0], l2 = [0]
输出:[0]
示例 3:

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

代码

ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    ListNode* head = nullptr, * tail = nullptr;
    // 进位初始变量为0
    int carry = 0;
    while (l1 || l2) {
        // 如果L1不为空,n1就为L1的第一个元素
        // 也就是说  个位数先相加   L2类似
        int n1 = l1 ? l1->val : 0;
        int n2 = l2 ? l2->val : 0;
        int sum = n1 + n2 + carry;
        // 如果 head 为空指针
        if (!head) {
            head = tail = new ListNode(sum % 10);
        }
        // 如果 head 不是空指针
        else {
            tail->next = new ListNode(sum % 10);
            tail = tail->next;
        }
        // 若sum>10 则进位为1
        carry = sum / 10;
        // L1 和 L2若存在其他位,向后移位
        if (l1) {
            l1 = l1->next;
        }
        if (l2) {
            l2 = l2->next;
        }
    }
    // 若最高位加完时,还有进位,那么新增一个最高位值为1 (即carry)
    if (carry > 0) {
        tail->next = new ListNode(carry);
    }
    return head;
}

3. 无重复字符的最长子串

题目:

示例 1:

输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:

输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:

输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

代码:

s.substr(i, rk - i + 1)
第一个参数是从i开始截取,第二个参数是截取几个元素

int lengthOfLongestSubstring(string s) {
    // 哈希集合,记录每个字符是否出现过
    unordered_set<char> occ;
    int n = s.size();
    // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
    int rk = -1, ans = 0;
    // 枚举左指针的位置,初始值隐性地表示为 -1
    for (int i = 0; i < n; ++i) {
        if (i != 0) {
            // 左指针向右移动一格,移除一个字符
            occ.erase(s[i - 1]);
        }
        // occ.count 存在该元素返回1,不存在该元素返回0
        while (rk + 1 < n && !occ.count(s[rk + 1])) {
            // 不断地移动右指针
            occ.insert(s[rk + 1]);
            rk++;
        }
        // 第 i 到 rk 个字符是一个极长的无重复字符子串
        cout << s.substr(i, rk - i + 1)<<'\n';
        ans = max(ans, rk - i + 1);
    }
    return ans;
}

int main() {
    string str = "abcabcbb";
    cout << lengthOfLongestSubstring(str);
}

4. 合并两个有序数组

本题是第五题的铺垫
代码参考王道考研教材

题目:

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
示例 2:
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。
示例 3:
输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

代码:

void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
    // K是sorted 数组的指针
    int p1 = 0, p2 = 0,k = 0;
    int *sorted = new int[m+n];
    // 若p1和p2都没有到数组末尾
    while (p1 < m && p2 < n) {
        if (nums1[p1] <= nums2[p2]) {
            sorted[k++] = nums1[p1++];
        }
        else {
            sorted[k++] = nums2[p2++];
        }
    }
    // 若P1还没有结束
    while (p1 < m) {
        sorted[k++] = nums1[p1++];
    }
    // 若P2还没有结束
    while (p2 < n) {
        sorted[k++] = nums2[p2++];
    }
    // 复制整个数组给nums1,并返回
    for (int i = 0; i != m + n; ++i) {
        nums1[i] = sorted[i];
    }
}

测试:

int main() {
    
    vector<int> a = { 1,2,3,0,0,0 };
    int m = 3;
    vector<int> b = { 2,5,6 };
    int n = 3;
    merge(a, m, b, n);
    for (int i = 0; i < a.size(); i++) {
        cout << a[i] <<" ";
    }
}

5.寻找两个正序数组的中位数

本题(log (m+n))时间复杂度的代码思路太难想了,出于应试考虑,修改了上题的一部分代码,时间复杂度达到了(m+n)/2

题目:

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O(log (m+n)) 。

示例 1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

代码:

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    int p1 = 0, p2 = 0,k = 0,num;
    int m = nums1.size();
    int n = nums2.size();

    int* sorted = new int[m + n];

    num = (m + n) / 2;
    // 如果是偶数
    if ((m + n) % 2 == 0) {
        while (p1 < m && p2 < n && k <= num) {
            if (nums1[p1] <= nums2[p2]) {
                sorted[k++] = nums1[p1++];
            }
            else {
                sorted[k++] = nums2[p2++];
            }

        }
        while (p1 < m && k <= num) {
            sorted[k++] = nums1[p1++];
        }
        while (p2 < n && k <= num) {
            sorted[k++] = nums2[p2++];
        }
        double medium = double(sorted[k - 1] + sorted[k - 2]) / 2;
        return medium;
    }
    // 如果是奇数
    else
    {
        while (p1 < m && p2 < n && k <= num) {
            if (nums1[p1] <= nums2[p2]) {
                sorted[k++] = nums1[p1++];
            }
            else {
                sorted[k++] = nums2[p2++];
            }

        }
        while (p1 < m && k <= num) {
            sorted[k++] = nums1[p1++];
        }
        while (p2 < n && k <= num) {
            sorted[k++] = nums2[p2++];
        }
        double medium = double(sorted[k - 1]);
        return medium;
    }
}

测试:

int main() {
    vector<int> a = { 1,3,5 };
    vector<int> b = { 2,4,6,7 };  
    double res;
    res = findMedianSortedArrays(a, b);
    cout << res << "\n";
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码魔法师!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值