面试问题

约 1691 字大约 6 分钟...

算法学习

  • 二分查找:给定升序数组和目标值,求目标值下标

    while(letf<=right){
        int mid=left+(right-left)/2;
        if(nums[mid]>target){
            right=mind-1;
        }else if(nums[mid]<target){
            left=mid+1;
        }else{
            return mid;//找到了
        }
    }
    
  • 移除元素:给定一个数组和移除的val,求数组新长度

    //1.
    for (int i = 0; i < size; i++) {
                if (nums[i] == val) { // 发现需要移除的元素,就将数组集体向前移动一位
                    for (int j = i + 1; j < size; j++) {
                        nums[j - 1] = nums[j];
                    }
                    i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                    size--; // 此时数组的大小-1
                }
            }
    return size;
    //2.
    int slowIndex = 0;//用于表示有多少个不是目标值
            for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
              //快指针持续往前走,慢指针只有和目标值不相等才往前走  
    					if (val != nums[fastIndex]) {//如果不等于,那么
                    nums[slowIndex++] = nums[fastIndex];
                }
    }
    return slowIndex;
    
  • 有序数组平方和:给定一个非递减数组,求每个数字平方和形成的非递减新数组

    //1.
    for(int i=0;i<nums.size();i++){
    	nums[i]*=nums[i];//先求平方
    }
    sort(nums.begin(),nums.end());//后排序
    
    //2.
    int k = nums.size() - 1;
    for (int i = 0, j = num.size() - 1; i <= j;) { // 注意这里要i <= j,因为最后要处理两个元素
    	//边平方边排序,左边比右边小
    	if(nums[i]*nums[i]<nums[j]*nums[j]){
    			result[k--]=nums[j]//说明最大值右边的
    			j--;右边往前移动
    	}else{
    			result[k--]=nums[i]//说明大值是左边的
    			i++;右边往前移动
    	}
    }
    
  • 长度最小的子数组:给定一个正整数s和一个正整数数组,求大于s的长度最小的子数组

    int result=INT32_MAX;//由于要比较谁更小,所以要拿一个最大值进行比较
    int sum=0;//子序列的和
    int sublength=0;//子序列长度
    for (int i = 0; i < nums.size(); i++) { // 设置子序列起点为i
    	sum=0;
    	for (int j = i; j < nums.size(); j++) { // 设置子序列终止位置为j
    		sum+=nums[j];//把起点和终点的值都加起来
    		if(sum>s){
    			sublength=j-i+1;
    			result=result<sublength?result:sublength;
    		}
    	}
    }
    return result==INT_MAX32?0:result;//如果还是最大值,那说明没找到,一个循环都没进,所以返回0
    
  • 螺旋数组:给定一个正整数n,生成一个包含 1 到 n^2 所有元素

    vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
    int startx=0,starty=0;//每次循环的起点
    int loop=n/2;//确定循环的次数:3--1(中间剩下一个点最后加),4--2
    int mid=n/2;
    int count=1;//给矩阵赋值的函数
    int offset=1;//控制每一圈遍历的长度
    int i,j;
    while (loop --) {
        i = startx;
        j = starty;
        // 模拟填充上行从左到右(左闭右开)
        for (j = starty; j < n - offset; j++) {
    	     res[startx][j] = count++;
         }
       // 模拟填充右侧从上到下(左闭右开)
       // 模拟填充下行从右到左(左闭右开)
       // 模拟填充左侧从下到上(左闭右开)
       // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
       startx++;
       starty++;
    	// offset 控制每一圈里每一条边遍历的长度
      offset += 1;
    }
    if(n%2) res[mid][mid]=count;//奇数,把中间的值给填上
    return res;
    
  • 反转字符串:将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出

    for(int i=0;j=s.size()-1;i<s.size()/2;i++,j--){
    	swap(s[i],s[j]);
    }
    void swap(char &s1,char &s2){
    	char tmp=s1;
    	s1=s2;
      s2=tmp;
    }
    
  • 反转字符串:给定一个字符串 s 和一个整数 k,每隔 2k 个字符的前 k 个字符进行反转

    string reverseStr(string s,int k){
    	for(int i=0;i<s.size();i+=2*k){
    			if(i+k<=s.size()){
    				reverse(s.begin()+i,s.begin()+i+k)
    			}else{
    				reverse(s.begin()+i,s.end());
    			}
    	}
    	return s;
    }
    
    
  • 替换空格:把字符串 s 中的每个空格替换成"%20"

    扩充数组到每个空格替换成"%20"之后的大小。然后从后向前替换空格,也就是双指针法

    int count=0;//统计空格个数
    int s_oldsize=s.size();
    for(int i=0;i<s.size();i++){
    	if(s[i]==" ") count++;
    }
    // 扩充字符串s的大小,也就是每个空格替换成"%20"之后的大小
    s.resize(s.size() + count * 2);//因为之前有一个空格,所以加2*count就够了
    int s_newsize=s.size();
    //j<i说明,空格补满了,前面都是字符了
    for(int i=s_newsize-1,j=s_oldsize-1;j<i;i--,j--){
    	if(s[j]!=" ") s[i]=s[j]
    	else{
    		s[i]="0";s[i-1]="2";s[i-2]="%";
    		i=i-2;//因为还有i--,所以-2就够了
    	}		
    }
    
    
  • ****翻转字符串里的单词:****输入: "the sky is blue",输出: "blue is sky the"

    //移除多余的空格
    void removeExtraSpaces(string& s) {
        for (int i = s.size() - 1; i > 0; i--) {
            if (s[i] == s[i - 1] && s[i] == ' ') {
                s.erase(s.begin() + i);
            }
        }
        // 删除字符串最后面的空格
        if (s.size() > 0 && s[s.size() - 1] == ' ') {
            s.erase(s.begin() + s.size() - 1);
        }
        // 删除字符串最前面的空格
        if (s.size() > 0 && s[0] == ' ') {
            s.erase(s.begin());
        }
    }
    	//反转字符串
     void reverse(string&s,int start,int end){
    		for(int i=start,int j=end;i<j;i++,j--){
    		 swap(s[i],s[j]);
    	}
    }
    
    string reverseWords(string s) {
            removeExtraSpaces(s); //去除多余空格,保证单词之间之只有一个空格,且字符串首尾没空格。
            reverse(s, 0, s.size() - 1);
            int start = 0; //removeExtraSpaces后保证第一个单词的开始下标一定是0。
            for (int i = 0; i <= s.size(); ++i) {
                if (i == s.size() || s[i] == ' ') { //到达空格或者串尾,说明一个单词结束。进行翻转。
                    reverse(s, start, i - 1); //翻转,注意是左闭右闭 []的翻转。
                    start = i + 1; //更新下一个单词的开始下标start
                }
            }
            return s;
        }
    
    
  • 左旋转字符串:给定字符串和数字k,把前k个字符串放到末尾: 输入: s = "abcdefg", k = 2,输出: "cdefgab"

    
    string reverseLeftWords(string s, int n) {
    	reverse(s.begin(),s.begin()+k);//s = "bacdefg"
    	reverse(s.begin()k+1,s.end());//s="bagfedc"
    	reverse(s.begin(),s.end());//s="cdefgab"
    }
    
  • 深度优先遍历和广度优先遍历的区别

    (1)深度优先遍历:对每一个可能的分支路径深入到不能再深入为止,而且每个结点只能访问一次。要特别注意的是,二叉树的深度优先遍历比较特殊,可以细分为先序遍历、中序遍历、后序遍历。具体说明如下:

    • 先序遍历:对任一子树,先访问根,然后遍历其左子树,最后遍历其右子树。
    • 中序遍历:对任一子树,先遍历其左子树,然后访问根,最后遍历其右子树。
    • 后序遍历:对任一子树,先遍历其左子树,然后遍历其右子树,最后访问根。

    (2)广度优先遍历:又叫层次遍历,从上往下对每一层依次访问,在每一层中,从左往右(也可以从右往左)访问结点,访问完一层就进入下一层,直到没有结点可以访问为止。

已到达文章底部,欢迎留言、表情互动~
  • 赞一个
    0
    赞一个
  • 支持下
    0
    支持下
  • 有点酷
    0
    有点酷
  • 啥玩意
    0
    啥玩意
  • 看不懂
    0
    看不懂
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.2