1、用c语言编写一个函数用来删除字符串中的空格并返回空格个数(不允许开辟空间)
int deletespace(char *str, char *res) {
int count = 0;
int i = 0;
while(*str != '\0'){
if (*str != ' ') {
res[i++] = *str;
}
else {
count++;
}
str++;
}
res[i + 1] = '\0';
return count;
}
int main() {
char str[] = "hello world";
cout << strlen(str) << endl;
char res[11] = "";
int count = deletespace(str, res);
cout << res << endl;
cout << count << endl;
system("pause");
return 0;
}
- 求n的阶乘末尾0的个数
int Count(int n)
{
int nCnt = 0;
while(n)
{
nCnt + = n / 5;
n /= 5;
}
return nCnt;
}
- 求两数的和
给出一个整数数组,请在数组中找出两个加起来等于目标值的数,
你给出的函数twoSum 需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2.。注意:下标是从1开始的
假设给出的数组中只存在唯一解
例如:
给出的数组为 {20, 70, 110, 150},目标值为90
输出 index1=1, index2=2
输入 [3,2,4],6
返回值 [2,3]
代码如下:
vector<int> twoSum(vector<int>& numbers, int target) {
// write code here
vector<int> res; //存储返回的结果
map<int,int> mp; //存储值和下表
for(int i = 0; i < numbers.size(); i++){
mp[numbers[i]] = i;
}
for(int i= 0; i < numbers.size(); i++){
//每遍历一个numbers[i]就去对应的mp里找有没有target - numbers[i]
//如果有就返回结果
//如果没有就找下一个
if(mp.find(target - numbers[i]) != mp.end() && i!= mp[target - numbers[i]]){
res.push_back(i+1);
res.push_back(mp[target - numbers[i]] + 1);
return res;
}
}
return res;
}
- 输入int数组 输出组成的最小值的字符串
static bool cmp(int a, int b)
{
string A = to_string(a) + to_string(b);
string B = to_string(b) + to_string(a);
return A < B; (当输出最大最大字符串时 A > B)
}
string GetMinNum(vector<int> nums)
{
string str = "";
std::sort(nums.begin(), nums.end(), cmp);
for(int i = 0; i < nums.size(); i++){
str += to_string(nums[i]);
}
return str;
}
5、有一个整数数组,请你根据快速排序的思路,找出数组中第K大的数。
给定一个整数数组a,同时给定它的大小n和要找的K(K在1到n之间),请返回第K大的数,保证答案存在。
输入
[1,3,5,2,2],5,3
返回值
2
int quick_sort(vector<int> &a, int start, int end, int n, int k){
int base = a[start];
int i = start;
int j = end;
int res = 0;
while(i < j){
while(i < j && a[j] >= base) --j;
while(i < j && a[i] <= base) ++i;
if(i < j)
std::swap(a[i], a[j]);
}
std::swap(a[j], a[start]);
if (n - j == k) return a[j];
else if (n - j < k) res = quick_sort(a, start, j-1, n, k);
else if (n - j > k) res = quick_sort(a, j+1, end, n, k);
return res;
}
int findKth(vector<int> a, int n, int K) {
// write code here
return quick_sort(a, 0, n - 1, n, K);
}
- 请实现有重复数字的升序数组的二分查找
给定一个 元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1
输入
[1,2,4,4,5],3
返回值
-1
示例3
输入
[1,1,1,1,1],1
返回值
0
int search(vector<int>& nums, int target) {
// write code here
if (nums.empty() || nums.size() == 0)
return -1;
int left = 0;
int right = nums.size() - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return nums[left] == target ? left : -1;
}
7.给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
思考:
整数数组 nums 中只包含一个元素;
整数数组 nums 中包含两个或两个以上元素。
思路
只包含一个元素,直接返回该元素;
包含两个或两个以上元素,暴力轮询或动态规划求乘积最大的连续子数组,返回乘积。
int maxProduct(vector<int>& nums) {
int size = nums.size();
/* 整数数组 nums 只包含一个元素 */
if (size == 1) {
return nums[0];
}
/* maxRes 记录整数数组 nums 中乘积最大的连续子数组的乘积 */
int maxRes = nums[0];
for (int i = 0; i < size; ++i) {
/* curMax 记录整数数组 nums 中当前乘积最大的连续子数组的乘积 */
int curMax = 1;
for (int j = i; j < size; ++j) {
curMax *= nums[j];
/* 不断更新 nums 中乘积最大的连续子数组的乘积 maxRes */
maxRes = max(maxRes, curMax);
}
}
return maxRes;
}
时间复杂度为O(n^2),但由于未开辟额外的空间,所以空间复杂度为O(1)
由于整数数组 nums 中的元素可能有正数、负数和 0,因此连续子数组中的元素也可能是这三种情况。
如果连续子数组中的元素存在负数,正数乘以负数就成负数,那么最大值乘以负数就变成了最小值,因此需要同时考虑当前连续子数组乘积的最大值curMax和最小值curMin。
注意点
整数数组 nums 中存在负数,当遍历到以nums[i](负数)结尾连续子数组时,需要交换 curMax 和 curMin。
int maxProduct(vector<int>& nums) {
int size = nums.size();
/* 整数数组 nums 只包含一个元素 */
if (size == 1) {
return nums[0];
}
/* curMax:以 nums[i] 结尾的当前乘积最大的连续子数组的乘积 */
/* curMin:以 nums[i] 结尾的当前乘积最小的连续子数组的乘积 */
int maxRes = nums[0], curMax = nums[0], curMin = nums[0];
for (int i = 1; i < size; ++i) {
/* nums[i] < 0 时,交换 curMax 和 curMin */
if (nums[i] < 0) {
swap(curMax, curMin);
}
/* 不断更新 curMax、curMin 和 maxRes */
curMax = max(curMax * nums[i], nums[i]);
curMin = min(curMin * nums[i], nums[i]);
maxRes = max(maxRes, curMax);
}
return maxRes;
}
由于只进行了一层遍历,因此其时间复杂度为O(n),同样由于未开辟额外的空间,所以空间复杂度为O(1)
- 给定一个数组,在数组中找到两位数,使得他们的之和最接近目标但不超过目标,返回他们的和
输入target = 15, array= [1, 3, 5, 11, 7]
输出 11 + 3 = 14
int GetValue(vector<int> &nums, int target)
{
if(nums.size() < 2){
return -1;
}
sort(nums.begin(), nums.end());
int left = 0;
int diff = INT_MAX;
int right = nums.size() -1;
while(left < right){
int nSum = nums[left] + nums[right];
if(target < nSums){
right --;
}
else
{
left++;
diff = min(diff, target - nSums);
}
}
return diff == INT_MAX ? -1 : target - diff;
}
8 . 已知数组中有一个数字出现的次数,超过数组长度的一半,要求找出这个数字。
即摩尔投票法,时间复杂度是O(N), 空间复杂度是O(1),能满足面试要求。思路是怎样的呢?
我们来看一种现实中的投票场景:
班级要开始选班长
要求半数以上通过
选出来的就是班长
我们先来看一种简单的情况:假如只有2个人A和B竞争班长这一职位。那么,在大家投票后,我们从投票箱中取数后,可以这样统计:
先抽一张票,如果是A,则记录当前胜利者为A,票数:1
再抽一张票,如果是A,则记录当前胜利者为A,票数:2
再抽一张票,如果是B,则抵消,记录当前胜利者为A,票数:1
再抽一张票,如果是B,则抵消,记录无当前胜利者
再抽一张票,如果是A,则记录当前胜利者为A,票数:1
…
如此循环,直到所有票统计完毕,最后有票的一方,就是胜利者,就是大家选出来的班长。
int solution(int a[], int n) {
int count = 0, value = a[0];
for(int i = 0; i < n; i++)
{
printf("log, i=%d, count=%d, value=%d\n", i, count, value);
if(count == 0)
{
value = a[i];
}
if(a[i] == value)
{
count++;
}
else
{
count--;
}
}
return value;
}
- 给一个正数数组,找出最小长度连续子数组,其和大于等于 m。
思路:
这题还是用双指针,首先用 i 遍历每一个位置,然后维护 a[j] ~ a[i] 之间的元素和。如果发现和大于等于 m ,那就更新最小长度,同时增大 j 直到区间和小于 m 。最终时间复杂度是 O(n) 的。
int minSubArrayLen(int m, vector<int>&nums, int n){
int j = 0, Sum = 0, res = INT_MAX;
for(int i = 0; i < n; i++){
Sum += nums[i];
while(Sum >= m){
res = min(res, i - j + 1);
Sum -= nums[j++];
}
}
return res;
}
10 给定一个数组arr,返回子数组的最大累加和
例如,arr = [1, -2, 3, 5, -2, 6, -1],所有子数组中,[3, 5, -2, 6]可以累加出最大的和12,所以返回12.
题目保证没有全为负数的数据
int maxsumofSubarray(vector<int>& arr) {
// write code here
if(arr.size() == 0){
return 0;
}
int ResMax = arr[0];
int Sum = arr[0];
for(int i = 1; i < arr.size(); i++)
{
Sum += arr[i];
Sum = max(arr[i], Sum);
ResMax = max(ResMax, Sum);
}
return ResMax;
}
11 给出一个数组 A,找到最大的 A[i] - A[j],要求 i > j。
这题很简单,直接遍历每个 A[i],维护它前面最小的那个数 minn,然后求出最大的 A[i] - minn
int GetMaxValue(vector<int>& nums)
{
int min = nums[0], res = INT_MIN;
for(int i = 1; i < nums.size(); i++){
res = max(res, nums[i] - min);
min = min(min, nums[i]);
}
return res;
}
12 手动实现智能指针shared_ptr
实现原理:采用引用计数器的方法,允许多个智能指针指向同一个对象,每当多一个指针指向该对象时,指向该对象的所有智能指针内部的引用计数加1,每当减少一个智能指针指向对象时,引用计数会减1,当计数为0的时候会自动的释放动态分配的资源。
智能指针将一个计数器与类指向的对象相关联,引用计数器跟踪共有多少个类对象共享同一指针
每次创建类的新对象时,初始化指针并将引用计数置为1
当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数
对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数
调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)
template<typename T>
class SharedPtr
{
public:
SharedPtr(T* ptr = NULL):_ptr(ptr), _pcount(new int(1))
{}
SharedPtr(const SharedPtr& s):_ptr(s._ptr), _pcount(s._pcount){
*(_pcount)++;
}
SharedPtr<T>& operator=(const SharedPtr& s){ //对象的拷贝,必须带着智能指针模板,否则就会出现对象引用计数丢失
if (this != &s)
{
if (--(*(this->_pcount)) == 0)
{
delete this->_ptr;
delete this->_pcount;
}
_ptr = s._ptr;
_pcount = s._pcount;
*(_pcount)++;
}
return *this;
}
T& operator*()
{
return *(this->_ptr);
}
T* operator->()
{
return this->_ptr;
}
~SharedPtr()
{
--(*(this->_pcount));
if (this->_pcount == 0)
{
delete _ptr;
_ptr = NULL;
delete _pcount;
_pcount = NULL;
}
}
private:
T* _ptr;
int* _pcount;//指向引用计数的指针
};
13 输入一个数组,调整数组中数字的顺序,使得奇数位于数组的前半部分,偶数位于数组的后半部分,要求时间复杂度为O(n)
bool bIsEvent(int n)
{
return (n&1) == 0; //true -偶数, false-奇数
}
void ReorderOddEvent(int *pData, int length){
if(pData == nullptr || length == 0){
return;
}
int *pBegin = pData;
int *pEnd = pData + length -1;
while(pBegin < pEnd){
if(!bIsEvent(*pBegin)){ //为奇数
pBegin++;
continue;
}
if(bIsEvent(*pEnd)){
pEnd --;
continue;
}
std::swap(*pBegin, *pEnd);
}
}