手撕代码

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;
}

  1. 求n的阶乘末尾0的个数
int Count(int n)
{
	int nCnt = 0;
	while(n)
	{
	   nCnt + = n / 5;
	   n /= 5;
	}
	return nCnt;
}
  1. 求两数的和
    给出一个整数数组,请在数组中找出两个加起来等于目标值的数,
    你给出的函数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;       
    }
  1. 输入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);
    }
  1. 请实现有重复数字的升序数组的二分查找
    给定一个 元素有序的(升序)整型数组 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)
  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;
}
  1. 给一个正数数组,找出最小长度连续子数组,其和大于等于 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);
   }
}
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值