【有书共读】《算法与数据结构题目最优解》(在线编程题总结1)
0. 说在前面
刚拿到这本书的时候,真的很激动,还有左大神的签名祝福,于是下定决心拜读一波,翻开才发现代码实现是基于java的,有点小失落,因为我学的是C++与python,后来硬着头皮看了下,确实解答的过程很详细。完全可以通过这个解答过程或者根据java代码改写为python或者C++代码,说实话,我也是不久前才看到群里说要检查读书笔记,就当是监督学习咯。我不是按照顺序来看的,接下来我将我在实习面试过程遇到的编程题和自己看的一些代码写下。
1. 阿里在线编程——快速排序(限时30分钟)
(1)C++代码
#include <iostream>
#include <vector>
#include <exception>
using namespace std;
// 分类 ------------ 内部比较排序
// 数据结构 --------- 向量
// 最差时间复杂度 ---- 每次选取的基准都是最大(或最小)的元素,导致每次只划分出了一个分区,需要进行n-1次划分才能结束递归,时间复杂度为O(n^2)
// 最优时间复杂度 ---- 每次选取的基准都是中位数,这样每次都均匀的划分出两个分区,只需要logn次划分就能结束递归,时间复杂度为O(nlogn)
// 平均时间复杂度 ---- O(nlogn)
// 所需辅助空间 ------ 主要是递归造成的栈空间的使用(用来保存left和right等局部变量),取决于递归树的深度,一般为O(logn),最差为O(n)
// 稳定性 ---------- 不稳定
void Swap(vector<int>& data, int i, int j)
{
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
int RandomInRange(int min, int max) //在min~max中随机生成一个值
{
int random = rand() % (max - min + 1) + min;
return random;
}
int Partition(vector<int>& data, int start, int end) //Partition函数
{
if (data.size() <= 0 || start < 0 || end >= data.size())
throw new std::exception("Invalid Parameters");
//int index = RandomInRange(start, end); //可以不调用RandomInRange函数
//Swap(data, index, end);
int small = start - 1;
for (int index = start; index < end; ++index)
{
if (data[index] < data[end])
{
++small;
if (small != index)
Swap(data, index, small);
}
}
++small;
Swap(data, small, end);
return small;
}
//递归快速排序
void QuickSort(vector<int>& data, int start, int end)
{
if (start >= end)
return;
int index = Partition(data, start, end); //基准的索引
QuickSort(data, start, index - 1);
QuickSort(data, index + 1, end);
}
int main()
{
//输入不定长的待排序列
vector<int> vec;
int temp;
char t;
cout << "输入待排序列为:";
do{
cin >> temp;
vec.push_back(temp);
} while ((t = cin.get()) != '\n');
/////////////////////////////////////////////////////////////////////////////////////
int n = vec.size();//待排序列的长度 ,若输入为数组A,则int n = sizeof(A) / sizeof(int);
cout << "排序前的结果为:";
for (int i = 0; i < n; i++)
{
cout << vec[i] << " ";
}
cout << endl;
/////////////////////////////////////////////////////////////////////////////////////
QuickSort(vec, 0, n - 1); //调用快速排序算法
/////////////////////////////////////////////////////////////////////////////////////
cout << "排序后的结果为:";
for (int i = 0; i < n; i++)
{
cout << vec[i] << " ";
}
cout << endl;
system("pause");
return 0;
}
(2)python代码:
# 快速排序
def quick_sort(array, l, r):
if l < r:
q = partition(array, l, r)
quick_sort(array, l, q - 1)
quick_sort(array, q + 1, r)
def partition(array, l, r):
x = array[r]
i = l - 1
for j in range(l, r):
if array[j] <= x:
i += 1
array[i], array[j] = array[j], array[i]
array[i + 1], array[r] = array[r], array[i + 1]
return i + 1
if __name__=="__main__":
arr = [int(i) for i in input().split()] # 输入待排序列
quick_sort(arr,0,len(arr)-1) # 快速排序
print(" ".join(str(i) for i in arr)) # 输出排序结果
详细信息与运行结果请见博客:https://blog.csdn.net/zichen_ziqi/article/details/80419920。
2. 爱奇艺在线编程——括号匹配(不适用栈,仅处理圆括号,限时15分钟)
说明:当输入为()(())(),返回true;当输入为)()()()()),返回false,时间15min。(不能使用栈)
很遗憾,当时确实没写完,后来自己下来反思总结写完了。如果能使用栈,15分钟问题不大,详细分析过程请见博客:https://blog.csdn.net/zichen_ziqi/article/details/80807989。下面是我笔试后自己想到的一种方法,具体过程如下:
(a)由于不能使用栈,将左括号定义为数值1,右括号定义为数值-1,存放到向量id(C++)或列表tmp (Python)中;
(b)初始化变量sum,用于判断总的求和结果是否等于0,若不等于0,则肯定不正确,若等于0,不一定正确;
(c)循环遍历输入的括号向量vec,判断当前括号属性的同时,进行累加求和,如果求和值小于等于-1,break(跳出循环);
(d)最后再检查sum是否等于0,此时若等于0,则为正确。
(1)C++代码
#include <iostream>
#include <vector>
using namespace std;
bool isRight(vector<char> &vec){
vector<int> id(vec.size()); //用于存放左右括号的属性:左括号用1表示,右括号用-1表示
int sum = 0;
bool index = false;
if (vec.size() <= 1 || vec[0]!='(' || vec.size()%2!=0){
return index;
}
for (int i = 0; i < vec.size(); i++){
if (vec[i] == '('){
id.push_back(1);
sum = id[i] + sum;
}
else if (vec[i] == ')'){
id.push_back(-1);
sum = id[i] + sum;
if (sum <= -1)
break;
}
}
if (sum == 0)
index = true;
return index;
}
int main(){
//输入不定长的括号
vector<char> vec;
char tmpCh;
char t;
cout << "输入一串括号为:";
do{
cin >> tmpCh;
vec.push_back(tmpCh);
} while ((t = cin.get()) != '\n');
//调用isRight函数
bool myRes = isRight(vec);
cout << myRes << endl;
system("pause");
return 0;
}
(2)python代码:
def isRight(str1):
index = False
sum = 0
tmp = []
if(len(str1)>=2 and len(str1)%2==0 and str1[0]=='('):
for id in range(len(str1)):
if str1[id] == '(':
tmp.append(1)
sum += tmp[id]
else:
tmp.append(-1)
sum += tmp[id]
if sum<=-1:
break
if sum == 0:
index = True
return index
if __name__ == "__main__":
try:
while True:
str1 = [i for i in input().split()]
print(isRight(str1)) # 返回判断结果
except:
pass
运行结果请见以上博客地址。
3. 设计一个有getMin功能的栈
解决思路:
(a)使用两个栈,一个栈用来保存当前的元素,记做:stackData,一个栈用来保存压入操作每一步的最小元素,记做:stackMin。
(b)入栈:当stackData栈中压入一个数据时,判断satckMin中是否为空。若为空,将该元素压入stackMin栈中。若不空,判断两者之间的大小,当前者小于或等于后者时,将前者中的数据压入后者中;当前者大于后者时,
不进行任何操作。
(c)出栈:保证stackMin中栈顶的元素是sattckData中最小的。
(1)C++代码#include<iostream>
#include <stack>
#include <cassert>
using namespace std;
//方法一: 一个辅助栈,如果这个栈为空,直接将元素入这个栈,如果辅助栈中有元素,将压入的元素和辅助栈顶元素比较,
//压入两者中较小的那个元素使得辅助栈总是维持栈顶元素为最小值。
//class Stack
//{
//public:
// void Push(int data)
// {
// stackData.push(data);
// if (stackMin.empty())
// {
// stackMin.push(data);
// }
// else
// {
// int tmp = stackMin.top();
// int min = data > tmp ? tmp : data;
// stackMin.push(min);
// }
// }
//
// void Pop()
// {
// assert(!stackData.empty() && !stackMin.empty());
// stackData.pop();
// stackMin.pop();
// }
//
// int GetMin()
// {
// assert(!stackMin.empty());
// return stackMin.top();
// }
//
//private:
// stack<int> stackData;
// stack<int> stackMin;
//};
//方法二: 一个辅助栈,如果这个栈为空,直接将元素入这个栈,如果辅助栈中有元素,将压入的元素和辅助栈顶元素比较,
//如果压入的元素小于等于辅助栈顶元素,者将这个元素入辅助栈,否则无操作,出栈的时候判断要出栈的元素是否等于辅助
//栈顶元素,如果是,也将辅助栈顶元素出栈。否则无操作。
class Stack
{
public:
void Push(int data)
{
stackData.push(data);
if (stackMin.empty())
{
stackMin.push(data);
}
else
{
if (data <= stackMin.top())
{
stackMin.push(data);
}
}
}
void Pop()
{
assert(!stackData.empty() && !stackMin.empty());
if (stackData.top() == stackMin.top())
{
stackMin.pop();
}
stackData.pop();
}
int GetMin()
{
assert(!stackMin.empty());
return stackMin.top();
}
private:
stack<int> stackData;
stack<int> stackMin;
};
int main()
{
Stack s;
//s.Push(5);
s.Push(36);
s.Push(15);
s.Push(95);
s.Push(50);
s.Push(53);
cout << s.GetMin() << endl;
system("pause");
return 0;
}//15
4. 剑指offer面试题30——包含min函数的栈
主要的思想与第3题差不多,其C++代码为:
class Solution {
public:
stack<int> stackData;//保存数据用的栈stackData
stack<int> stackMin;//保存最小的数的栈stackMin,其中它的栈顶始终为最小的数
void push(int value) {
stackData.push(value);
if(stackMin.empty())
stackMin.push(value);//如果stackMin为空,则value是最小的值,入栈
else{
if(stackMin.top()>=value)
stackMin.push(value);//否则当value小于等于stackMin的栈顶元素时,入栈(等于的时候也入栈是因为我考虑有相同的数)
}
}
void pop() {
if(stackData.top()==stackMin.top())//如果出栈的数刚好是最小的数,那么stackMin也应该出栈
stackMin.pop();
stackData.pop();
}
int top() {
return stackData.top();//栈顶元素应返回stackData的栈顶元素
}
int min() {
return stackMin.top();//stackMin的栈顶元素即是最小的数
}
};
5. 剑指offer面试题31——栈的压入、弹出序列
解决思路:
(a)当栈为空或者栈顶元素和popV当前元素不相等时,将pushV当前元素压入;
(b)当栈顶元素与popV当前元素相等时,将栈顶元素弹出,并移至popV下一个元素;
(c)如果需要压入的元素个数大于pushV的元素个数,说明popV不可能是pushV的弹出序列。
(b)当栈顶元素与popV当前元素相等时,将栈顶元素弹出,并移至popV下一个元素;
(c)如果需要压入的元素个数大于pushV的元素个数,说明popV不可能是pushV的弹出序列。
C++代码为:
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
//特殊输入测试
if(pushV.empty() || popV.empty() || pushV.size()!=popV.size())
return false;
stack<int> mystack;//定义一个辅助栈
int index=0;
for(int i=0;i<popV.size();i++){
//当辅助栈为空或者栈顶元素和popV当前元素不相等时,将pushV当前元素压入
while(mystack.empty()||mystack.top()!=popV[i]){
if(index>=pushV.size())
//如果需要压入的元素个数大于pushV的元素个数,说明popV不可能是pushV的弹出序列
return false;
mystack.push(pushV[index++]);
}
//当栈顶元素与popV当前元素相等时,将栈顶元素弹出,并移至popV下一个元素
if(mystack.top()==popV[i])
mystack.pop();
}
return true;
}
};
6. 写在最后
暂时就写这5个吧,其他的编程题我也正在学习,秋招在即,复习看书,刷题,编程练习,晚上睡觉前听着歌刷面经已经成为每天的必修课。希望现在的坚持没有白费,加油,老铁们!
#笔试题目##内推##实习#
查看7道真题和解析


基恩士成长空间 440人发布