C++ 练手

#include<vector>

#include<limits>
// 包含INT_MAX, INT_MIN,FLT_MAX, FLT_MIN 等定义

#include<algorithm> → min() max()
//int new_i= min(m-1, i+k/2-1);
//int new_j= min(n-1, j+k/2-1);

#include <string>

912. 排序数组

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        int n= nums.size()-1;
        quicksort(nums, 0, n);
        return nums;
    }
//快排
void quicksort(vector<int>& nums,int left, int right ){
            if(left>right){
                return;
            }
            int i,j,temp;
            i= left;
            j= right;
            temp= nums[left];
            while(i!=j){
                while(nums[j]>=temp && i<j){
                    j--;
                }
                while(nums[i]<=temp && i<j){
                    i++;
                }
                if(i<j){
                    int t;
                    t= nums[i];
                    nums[i]= nums[j];
                    nums[j]= t;
                }
            }
            nums[left]= nums[i];
            nums[i]= temp;

            quicksort(nums,left,i-1);
            quicksort(nums,i+1,right);

        }
};
class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        int n= nums.size()-1;
        quicksort(nums, 0, n);
        return nums;
    }
//快排(优化)
void quicksort(vector<int>& nums,int left, int right ){
            if(left>right){
                return;
            }
            int i,j,temp;
            i= left;
            j= right;
            //随机枢轴
            int ra= left+ rand()%(right-left+1);
            swap(nums[left],nums[ra]);
            temp= nums[left];

            while(i!=j){
                while(nums[j]>=temp && i<j){
                    j--;
                }
                while(nums[i]<=temp && i<j){
                    i++;
                }
                if(i<j){
                    swap(nums[i],nums[j]);
                }
            }
            swap(nums[left],nums[i]);

            quicksort(nums,left,i-1);
            quicksort(nums,i+1,right);

        }
};
class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        int n= nums.size()-1;
        quicksort(nums, 0, n);
        return nums;
    }
//快排(再优化)
void quicksort(vector<int>& nums,int left, int right ){
            if(left>right){
                return;
            }
            int i,j,temp;
            i= left;
            j= right;
            //随机枢轴
            int ra= left+ rand()%(right-left+1);
            swap(nums[left],nums[ra]);
            temp= nums[left];

            while(i!=j){
                while(nums[j]>=temp && i<j){
                    j--;
                }
                nums[i]= nums[j];
                while(nums[i]<=temp && i<j){
                    i++;
                }
                nums[j]= nums[i];
            }
            nums[i]= temp;

            quicksort(nums,left,i-1);
            quicksort(nums,i+1,right);

        }
};

7. 整数反转7. 整数反转


#include<limits>
// 包含INT_MAX, INT_MIN,FLT_MAX, FLT_MIN 等定义

class Solution {
public:
    int reverse(int x) {
        int num= 0;
        while(x!= 0){
            if(num> INT_MAX/10 || num< INT_MIN/10)return 0;
            //提前判溢
            num= num*10+ x%10;
            x= x/10;    
        }
        return num;
    }
};

1979. 找出数组的最大公约数

class Solution {
public:
    int findGCD(vector<int>& nums) {
        //int min= nums[0], max= nums[0];
        int min= INT_MAX, max= INT_MIN;
        //for(int num : nums) 用于遍历容器 nums 中的每个元素
        //for(int i= 0; i<sizeof(nums)/sizeof(nums[0]); i++)如果nums为空,访问其元素会报错
        for(int num: nums){
            if(num>max) max= num;
            if(num<min) min= num;
        }
    
        return gcd(max,min);
    }
    //辗转相除
    int gcd(int m, int n){
        while(m%n!= 0){
            int r= m%n;
            m= n;
            n= r;
        }
        return n;
    }
    
 /*
    int gcd(int m, int n){
        if(m%n==0)return n;
        else return gcd(n, m%n);
    }
*/
};

66. 加一

class Solution {
public:
    vector<int> plusOne(vector<int>& digits) {
        //求数组长度 .size()
        int n= digits.size();
        if(digits[n-1]!= 9){
            digits[n-1] +=1;
            return digits;
        }
   
        int sum= 0;
        for(int num: digits) sum= sum*10+num;
        sum +=1;

        //#inculde<cmath>   = pow(double base, double exponent)  平方项(double型)
        //#inculde<cmath>   = sqrt()                             开根号
        //#include<cmath>   =log() 以e为底 =log10() 以10为底  =log()/log(m) 以m为底
        if(sum/int(pow(10,n))== 0){
            for(int i= n-1 ; i>-1; i--){
                digits[i]= sum%10;
                sum= sum/10;
            }
            return digits;
        }
        
//int arr[9]; //静态数组,不允许改变,定义时得是常数,如9
//#include<vector> 
//vector 动态数组,它允许你在运行时动态地插入和删除元素
//vector<int> v2(10, 0); //构造含有10个0的int型容器
//vector<int> v3(v2); //拷贝构造int类的v2容器的复制品
//v.insert(v.end(), 2, 6);//在最后一个位置插入2个 6
//v.insert(v.begin(), 3);// 在第一个元素前插入3
//v.insert(v.begin(), v1.begin(), v1.end());//从v头开始,连续插入v1区间[begin, end]的所有元素
//v.emplace(arr.begin(), 10);//在容器中只加一个元素
//v.emplace_back(1);//在容器中末尾只加一个元素
//v.erase(v.begin());// 删除指定位置的元素
//v.erase(v.begin(), v.begin() + 2);// 删除指定区间的元素

        vector<int> vec(n+1);
        for(int i= 0; i<n+1; i++){
                vec[n-i]= sum%10;
                sum= sum/10;
            }
        return vec;

        //在子函数中,定义的数组变量是不允许返回的
    }
};

我艹艹艹,溢出了

修改

class Solution {
public:
    vector<int> plusOne(vector<int>& digits) {
        int n= digits.size();
        int flag= 0;
        digits[n-1]= digits[n-1]+1;
        for(int i= n-1; i>-1; i--){
            if(digits[i]==10){
                digits[i]= 0;
                if(i!=0)digits[i-1]= digits[i-1]+1;
                else flag= 1;                
            }
        }
        if(flag==0)return digits;

        vector<int> v(n+1,0);
        v[0]= 1;
        return v;
    }
};

204. 计数质数

class Solution {
public:
    int countPrimes(int n) {
        //1既非质数(素数)也非合数
        if(n==0 || n== 1)return 0;
        else if(n==2 || n==3 )return n-2;
        else{
            int count= 2;
            for(int i=4; i<n; i++){
                int flag= 0;
                for(int j=2; j*j<=i; j++){
                    //continue:跳出当前循环,即不执行continue后的语句,直接进入下次循环
                    //break:跳出for循环本身
                    if(i%j==0){
                        flag= 1;
                        break;
                    }
                }
                if(flag== 0)count++;
            }
            return count;
        }
    }
};

枚举没有考虑到数与数关联性,因此难以再继续优化时间复杂度。

方法二:埃氏筛

class Solution {
public:
    int countPrimes(int n) {
        vector<int> isPrim(n,1);
        int count= 0;
        for(int i= 2; i<n; i++){
            if(isPrim[i]==1){
                count+= 1;
                if(i< n){
                    for(int j= i; j<n; j+= i){
                        isPrim[j]= 0;
                    }
                }
            }
        }
        return count;
    }
};

67. 二进制求和

class Solution {
public:
    string addBinary(string a, string b) {
        int al= a.size();
        int bl= b.size();
        //"aacb"= "aa"+"cb"           //字符串拼接
        while(al<bl){
            a= '0'+a;
            al++;
        }
        while(bl<al){
            b= '0'+b;
            bl++;
        }
        //st= "adfg";  → st[0]= a;
        //'B'= 'A'+1;                //字符串加减
        int carry_flag= 0;           //进位符号carry_flag
        for(int i= al-1; i>=0; i--){
            int dt= a[i]-'0'+ b[i]-'0' +carry_flag; //增量dt
            a[i]= dt%2+'0';
            carry_flag= dt/2;
        }
        if(carry_flag!= 0){
            a= '1'+a;
        }
        return a;
    }
};

27. 移除元素

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int count= 0;
        for(int i= 0; i<nums.size(); i++){
            if(nums[i]!=val)count++;
        }
        //区间划分,双指针
        int di= -1;     
        for(int j= 0; j<nums.size(); j++){
            if(nums[j]!=val){
                di++;
                if(di!=j){
                    swap(nums[di],nums[j]);
                }          
            }
        }
        return count;
    }
};

26. 删除有序数组中的重复项

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        //非严格递增:一个序列中的元素从小到大排列,但是可以有相同的元素
        
        //写法1 区间划分
        /*
        int di= 0;
        for(int j= 1; j<nums.size();j++){
            if(nums[j]!=nums[j-1]){
                di++;
                nums[di]= nums[j];
            }
        }
        return di+1;
        */
        
        //写法2 快慢指针
        int fast= 1, slow= 0;
        while(fast<nums.size()){
            if(nums[fast]!=nums[fast-1]){
                slow++;
                nums[slow]= nums[fast];
            }
            fast++;
        }
        return slow+1;
    }
};
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
    if(nums.size()<=2){
        return nums.size();
    }
    
    int fast= 2, slow= 2;
    while(fast<nums.size()){
        //nums[slow]=nums[fast]的条件,nums[fast]与有序序列前k位不同
        if(nums[fast]!=nums[slow-2]){
            nums[slow]= nums[fast];
            slow++;
        }
        fast++;
    }
    return slow++;
    }
};

88. 合并两个有序数组

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        //法1:双指针i,j
        //将nums2插入nums1,遍历nums2,下标j
        //nums1中找到第一个大于等于nums2的或超出nums1有序序列边界的,下标i
        //后移1位
        //nums1[i]= nums2[j]
        /*
        int i= 0;
        for(int j= 0; j<n; j++){
            while(nums1[i]<nums2[j] && i<m+j){
                i++;
            }
            for(int k= m+n-1; k>i; k--){
                nums1[k]= nums1[k-1];
            }
            nums1[i]= nums2[j];
        */
        //法2:辅助数组(空间换时间),双指针
        vector<int> v(nums1);
        int i= 0, j= 0;
        while(i+j<m+n){
            if(n==0)break;
            //注:写成if(v[i]<=nums2[j] && i<m) || j==n) 可能会堆缓冲区溢出heap-buffer-overflow
            if(j==n || (v[i]<=nums2[j] && i<m)){
                nums1[i+j]= v[i];
                i++;
            }else{
                nums1[i+j]= nums2[j];
                j++;
            }
        }
 
    }
};

4. 寻找两个正序数组的中位数  (二分查找,递归,数学)

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int Len= nums1.size()+nums2.size();
        if(Len%2==1)return GetMid(nums1,nums2,Len/2+1,0,0);
        else return (GetMid(nums1,nums2,Len/2,0,0)+GetMid(nums1,nums2,Len/2+1,0,0))/2;
        }
    //找两个有序数组A,B中的第k小的数,i,j分别为数组下标(索引) 

    //法1:俩下标针遍历,时间复杂度O(m+n);

    //法2:二分查找,时间复杂度O(log(m+n));
    /*
      比较A[k/2−1]和B[k/2−1]
      由于A[k/2−1]和B[k/2−1]前面分别有k/2−1个元素
      对于A[k/2−1]和B[k/2−1]中的较小值,最多只会有(k/2−1)+(k/2−1)≤k−2个元素比它小
      那么它就不能是第k小的数了
    */  
    double GetMid(vector<int>& v1, vector<int>& v2, int k, int i, int j){
        int m= v1.size();
        int n= v2.size();

        if(i==m)return v2[j+k-1];
        else if(j==n)return v1[i+k-1];
        else if(k==1)return min(v1[i],v2[j]);
        
        //#include<algorithm> → min() max()
        int new_i= min(m-1, i+k/2-1);
        int new_j= min(n-1, j+k/2-1);
        if(v1[new_i]<v2[new_j]){
            k= k-(new_i-i+1);
            i= new_i+1;
            return GetMid(v1, v2, k, i, j);
        }else{
            k= k-(new_j-j+1);
            j= new_j+1;
            return GetMid(v1, v2, k, i, j);
        }
    }
};

382. 链表随机节点

/**
 * struct ListNode {
 *     int val;
 *     ListNode *next;
       // 默认构造函数,初始化节点值为0,指针为nullptr(空指针)
 *     ListNode(): val(0), next(nullptr){}
       // 构造函数,使用一个整数初始化节点值,指针默认为nullptr
 *     ListNode(int x): val(x), next(nullptr){}
       // 构造函数,使用一个整数初始化节点值,同时设置指向下一个节点的指针
 *     ListNode(int x, ListNode *next): val(x), next(next){}
 * };

   // 创建单个节点
   ListNode* node1 = new ListNode(1); // val = 1, next = nullptr
 */

class Solution {
public:
    vector<int> v;
    // Solution类的构造函数,用于初始化一个Solution对象
    Solution(ListNode* head) {
        while(head!= NULL){
            v.emplace(v.end(),head->val);
            head= head->next;
        }
    }
    
    int getRandom() {
        //#include <stdlib.h> → rand()
        return v[rand()%v.size()];
    }
};

/**
 //创建一个Solution类的对象 obj,并将其分配在堆内存上
 * Solution *obj= new Solution(head);
 * int param_1= obj->getRandom();
 */

203. 移除链表元素

/**
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        //题目不带头节点(哑节点),故先建一个头节点
        ListNode* real_head= new ListNode(0,head);
        ListNode *pre= real_head, *p= pre->next;

        while(p){
            if(p->val==val){
                pre->next= p->next;
                //使用delete来释放通过new分配的内存
                delete(p);
                p= pre->next;
            }else{
                pre= pre->next;
                p= pre->next;
            }
        }
        return real_head->next;
    }
};

237. 删除链表中的节点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    void deleteNode(ListNode* node) {
        ListNode* p_pre= node;
        ListNode* p= node->next;
        while(p->next!=NULL){
            p_pre->val= p->val;
            p_pre= p_pre->next;
            p= p->next;
        }
        p_pre->val= p->val;
        p_pre->next= NULL;
    }
};

206. 反转链表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head==NULL)return head;
        //new一个结构体
        ListNode* L= new ListNode();
        //头插法
        ListNode* r;
        while(head!=NULL){
            r= head->next;
            head->next= L->next;
            L->next= head;
            head= r;
        }
        L= L->next;
        return L;
    }
};

92. 反转链表 II

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        ListNode* h= new ListNode();
        h->next= head;

        ListNode* p= h;
        for(int i= 0; i<left-1; i++){
            p= p->next;
        }
        ListNode* r;
        ListNode* q= p->next;
        ListNode* first_q= q; 
        for(int i= left; i<=right; i++){
            r= q->next;
            if(q==first_q)q->next= NULL;
            else q->next= p->next;
            p->next= q;
            q= r;
        }
        first_q->next= q;
        head= h->next;  
        return head;    
    }
};

1381. 设计一个支持增量操作的栈

class CustomStack {
public:
    vector<int> data;
    int top;

    //b.resize(a,0):改变容器的大小,且创建对象
    CustomStack(int maxSize) {
        data.resize(maxSize);
        top= -1;
    }
    
    void push(int x) {
        //stk.size()为无符号整型,改为(int)stk.size()
        if(top<(int)data.size()-1){
            top++;
            data[top]= x;
        }   
    }
    
    int pop() {
        if(top!=-1){
            top--;
            return data[top+1];
        }else{
            return -1;
        }
        
    }
    
    void increment(int k, int val) {
        for(int i= 0; i<=top && i<k; i++){
            data[i]= data[i]+val;
        }
    }
};
/**
 * Your CustomStack object will be instantiated and called as such:
 * CustomStack* obj = new CustomStack(maxSize);
 * obj->push(x);
 * int param_2 = obj->pop();
 * obj->increment(k,val);
 */

假设表达式中允许包含圆括号、方括号和大括号3种括号(有优先级),编写一个算法判断表达式中的括号是否正确配对。

(链栈的结构体、一般操作定义)

typedef struct linknode{
  char data;
  struct linknode *next;
}LinkStack;

void InitStack(LinkStack *&st){
  st= (LinkStack*)malloc(sizeof(LinkStack));
  st->next= NULL;
}

bool Push(LinkStck *&st, char e){
  LinStack *p;
  p= (LinkStack*)malloc(sizeof(LinkStack));
  p->data= e;
  
  p->next= st->next;
  st->next= p;
  return true;
}

bool Pop(LinkStack *&st, char &e){
  if(st->next==NULL)return false;
  LinkStack *p;
  p= st->next;
  e= p->data;
  
  st->next= p->next;
  free(p);
  return true;
}

bool GetTop(LinkStack *st, char &e){
  if(st->next==NULL)return false;
  e= st->next->data;
  return true;
}

bool StackEmpty(LinkStack *st){
  if(st->next==NULL)return true;
  else return false;
}

void DestroyStack(LinkStack *&st){
  LinkStack *p_pre=st, *p=p_pre->next;
  while(p!=NULL){
    free(p_pre);
    p_pre= p;
    p= p->next;
  }
  free(p);
}



bool IsMatch(char a[], int n) {
  LinkStack *st;
  InitStack(st);
  int e;
  for(int i= 0; i<n; i++){
    switch(a[i]){
      case '(':
        Push(st,a[i]);
        break;
      case '[':
        Push(st,a[i]);
        break;
      case '{':
        Push(st,a[i]);
        break;

      case ')':
        if (Pop(st,e)==true && e!= '(') return false;
        break;
      case ']':
        if (Pop(st,e)==true && e!= '[') return false;
        break;
      case '}':
        if (Pop(st,e)==true && e!= '{') return false;
        break;
      default:
        break;
    }
  }
  if (IsEmpty(st)==true)
    return true;
  else return false;
}

设从键盘输入一个序列的字符a_1, a_2, ... , a_n。设计一个算法实现这样的功能:

若a_i为数字字符,a_i进队;若a_i为小写字母,将队首元素出队;

若a_i为其他字符,表示输入结束。

要求使用环形队列

# define MaxSize 50

typedef struct{
  int data[MaxSize];
  int front,rear;
}SqQueue;

void InitQueue(SqQueue *&qu){
  qu= (SqQueue*)malloc(sizeof(SqQueue));
  qu->front= qu->rear= 0;
}

bool enQueue(SqQueue *&qu, int e){
  if((qu->rear+1)%MaxSize==qu->front)return false;
  else{
    qu->rear= (qu->rear+1)%MaxSize;
    qu->data[q->rear]= e;
    return true;
  }
}

bool deQueue(SqQueue *&qu, int &e){
  if(qu->rear==qu->front)return false;
  else{
    qu->front= (qu->front+1)%MaxSize;
    e= qu->data[qu->front];
    return true;
  }
}

bool QueueEmpty(SqQueue *qu){
  if(qu->front=qu->rear)return true;
  else return false;
}

int QueueCount(SqQueue *qu){
  return (qu->rear-qu->front+MaxSize)%MaxSize;
}

void DestroyQueue(SqQueue *&qu){
  free(qu);
}

void processInput(){
  SqQueue *qu;
  qu= InitQueue(qu);
  char input;
  while(true){
    scanf('%c', &input)
    //isdigit是C++用于判断一个字符是否是数字字符('0' 到 '9')的函数 --#include <cctype>
    if(isdigit(input)){
      if(enQueue(qu, input))print("%c入队", input);
    }
    else if(islower(input)){
      char out;
      if(deQueue(qu, &out))print("%c出队",out)
    }else break;
  }
}

int main() {
  processInput();
  printf("over");
  return 0;
}

KMP算法(匹配模式串) 看看

//模式串t的next数组
//j 序号,t[j] 元素,next[j]=k 记录t[j]之前与t开头相同字符的个数

//无论是否加&,在函数中修改数组的值都可以传递回去
void GetNext(char t[], vector<int> next){
  t_size= sizeof(t)/sizeof(t[0]);
  int j,k;
  j= 0; k=-1;
  next[0]= -1;
  //next[j+1]根据t[j]是否可纳入t[0]~t[k]得出
  while(j<t_size-1){
    if(k==-1 || t[k]==t[j]){
      j++; k++;
      next[j]= k;
    }else k= next[k];
    //k的回退
  }
}


int KMPIndex(char s[], char t[]){
  //#include <vector>
  vector<int> next(t.size());
  GetNext(t,next);

  s_size= sizeof(s)/sizeof(s[0]);
  t_size= sizeof(t)/sizeof(t[0]);
  int i,j;
  i= 0; j= 0;
  while(i<s_size && j<t_size){
    if(j==-1 || s.data[i]==t.data[j]){
      i++; j++;
    }else j= next[j];
  }
  if(j==t__size)return(i-t_seze);
  else return -1;
}
/*
1、sizeof():返回静态数组所占总空间的字节数
(1)、对于整型字符型数组
(2)、对于整型或字符型指针
2、 .size():返回vector或stringh或array容器元素个数

3、strlen():返回char a[]的长度 #include <cstring>
*/

//模式串t的nextval数组
void GetNextval(char t[], vector<int> nextval){
  //#include <cstring>
  //strlen()求char a[]字符个数 
  t_size= strlen(t);
  int j,k;
  j=0; k=-1;
  nextval[0]= -1;

  while(j<t_size-1){
    if(k==-1 || t[j]==t[k]){
        j++; k++;
        if(t[j]==t[k])nextval[j]= nextval[k];
        else nextval[j]= k;
    }else k= nextval[k];
  }
  
}

面试题 08.06. 汉诺塔问题

学习递归

n A B C

将A的n环借助B移动到C

      递归终止条件: A只有一环,则将该环直接移动到C

      将A的前n-1环借助C移动到B

      将A的第n环移动到C

      将B的n-1环借助A移动到C

class Solution {
public:
    void hanota(vector<int>& A, vector<int>& B, vector<int>& C){
        int n= A.size();
        Hanoi(n,A,B,C);       
    }

    void Hanoi(int n, vector<int>& A, vector<int>& B, vector<int>& C){
        if(n==1){
            move(A,C);
            return;
        }
        Hanoi(n-1,A,C,B);
        move(A,C);
        Hanoi(n-1,B,A,C);
    }

    void move(vector<int>& A, vector<int>& C){
        //写法1
        C.push_back(A.back());
        A.pop_back();
        //写法2
        //C.insert(C.end(),A.back());
        //A.erase(A.end()-1);
    }

    //A.back()  返回的是容器最后一个元素的值
    //A.front() 返回的是容器第一个元素的值
    //对vector容器进行栈操作 A.push_back(Element), A.pop_back()
    //对于vector<int> 类型的容器,你只能使用push_back(),而不能直接使用push_front()

    //进行A.insert(),A.erase()时,只能对容器进行操作
    //A.end()   是一个迭代器,返回一个指向容器最后一个元素的下一个位置
    //          若需要最后一个元素的迭代器,用A.end()-1
    //A.begin() 是一个迭代器,返回一个指向容器第一个元素的迭代器
};

已知A[0..n-1]为实数数组,设计一个递归算法求这n个元素的平均值。

double average(int A[], int n){
  //递归出口
  if(n==1)return A[0];
  //递归主体
  return (A[n-1]+average(A, n-1)*(n-1))/n
}

上楼可以一步上一个台阶,也可以一步上两阶,设计一个递归算法,计算共有多少种不同的走法。

斐波那契数列问题

递归公式可以表示为: f(n)=f(n−1)+f(n−2)

int fun(int step_nums) {
  if (step_nums<=0) return 0;
  if (step_nums==1) return 1;
  if (step_nums==2) return 2;
  return fun(step - 2) + fun(step - 1);
}

设有一个不带表头结点的单链表L ,设计两个递归算法,traverse(L)正向输出单链表L中的所有结点值,traverseR(L)反向输出单链表L中的所有结点值。

typedef struct LNode{
  int data;
  struct LNode *next;
}LinkList;

void traverse(LinkList* L) {
  if(L==NULL) return;
  printf('%d\t',L->data);
  traverse(L->next);
}

void traverseR(LinkList* L) {
  if (L==NULL) return;
  traverse(L->next);
  printf('%d\t',L->data);
}

设有一个不带表头结点的单链表L,设计两个递归算法,del(L, x)删除单链表L中第一个值为x的结点, delall(L, x)删除单链表L中所有值为x的结点。

typedef struct LNode{
  int data;
  struct LNode *next;
}LinkList;

void del(LinkList* L, int x) {
  if (L==NULL) return;
  if (L->data==x) {
    if(L->next!==NULL){
      L->data= L->next->data;
      L->next= L->next->next;
    }else L= NULL;   
    return;
  }
  del(L->next, x);
}

void delall(LinkList* L, int x) {
  if (L==NULL) return;
  delall(L->next, x);
  if (L->data==x) {
    if(L->next!==NULL){
      L->data= L->next->data;
      L->next= L->next->next;
    }else L= NULL;   
    return;
  }
}

设有一个不带表头结点的单链表L,设计两个递归算法,maxnode(L)返回单链表L中的最大结点值, minnode(L)返回单链表 L中的最小结点值。

int maxnode(LinkList* L){
  if (L==NULL) return;
  if (L->next==NULL)return L->data;

  int max= maxnode(L->next);
  if(max>L->data)return max;
  else return L->data;
}

int minode(LinkList* L){
  if (L==NULL) return;
  if (L->next==NULL)return L->data;

  int min= minode(L->next);
  if(min<L->data)return min;
  else return L->data;
}

234. 回文链表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        //ListNode *L;
        //L= (ListNode*)malloc(sizeof(ListNode))
        ListNode* L= new ListNode();
        ListNode* h= head;
        while(h!=NULL){
            ListNode* t= new ListNode(h->val);
            t->next= L->next;
            L->next= t;

            h= h->next;
        }
        h= head;
        while(h!=NULL){
            if(h->val!=L->next->val)return false;
            h= h->next;
            L= L->next;
        }
        return true;       
    }
};

xh-10.2. 约瑟夫环问题

class Solution {
public:
    vector<int> Joseph_circle(vector<int>& people, int k) {
        vector<int> v;
        int now= 0;
        int num= people.size();
        for(int i= 0; i<num; i++){
            //定位
            now= (now+k-1)%people.size();
            //插入
            v.insert(v.end(),people[now]);
            //删除
            people.erase(people.begin()+now);
        }
        return v;
    }
};

直接返回的递归传入引用变量的递归

二叉树的定义具有递归性

Q13:
假设二叉树中的每个结点为单个字符,采用二叉链存储结构存储。
设计一个算法,计算一棵给定二叉树b中的所有单分支结点个数。

#### 答案:
```cpp
typedef struct{
    char data;
    struct *rchild, *lchild;
}BtNode;

//直接返回
int SingleNodeCount(BtNode* root){
  if(root==NULL)return 0;
  //if(root->lchild ^ root->rchild) return 1+SingleNodeCount(root->lchild)+SingleNodeCount(root->rchild);
   if ((root->lchild==NULL && root->rchild!=NULL) || (root->lchild!=NULL && root->rchild==NULL)){
        return 1+SingleNodeCount(root->lchild)+SingleNodeCount(root->rchild);
    }
  return SingleNodeCount(root->lchild)+SingleNodeCount(root->rchild);
}
//C++ 中,^是异或运算符,用于整数值的运算,而不是用于判断左右孩子的存在与否


//传入引用变量
void SingleNodeCount(BtNode* root, int& count= 0){
  if((root->lchild==NULL && root->rchild!=NULL) || (root->lchild!=NULL && root->rchild==NULL)) ++count;
  if(root->lchild) SingleNodeCount(root->lchild, count);
  if(root->rchild) SingleNodeCount(root->rchild, count);
}
```
Q14:
假设二叉树中的每个结点值为单个字符,采用二叉链存储结构。
设计一个算法,求二叉树b中的最小结点值。

#### 答案:
```cpp
typedef struct{
    char data;
    struct *rchild, *lchild;
}BtNode;

#include <climits>  //确保包含 CHAR_MAX
char Min(BtNode* root){
    if(root==NULL) return CHAR_MAX; //空树返回最大值

    char minVal= root->data; //假设当前结点值最小
    char lMin= Min(root->lchild);  //递归找左子树最小值
    char rMin= Min(root->rchild); //递归找右子树最小值
    // 取最小值
    if(lMin<minVal) minVal= lMin;
    if(rMin<minVal) minVal= rMin;

    return minVal;
}


#include <climits>
void Min(BtNode* root, char& min= CHAR_MAX) {
  if(root==NULL)return;

  min= (min<root->data) ? min:root->data;
  if(root->lchild) Min(root->lchild, min);
  if(root->rchild) Min(root->rchild, min);
}
```
Q16:
假设二叉树中的每个结点值为单个字符,采用二叉链存储结构存储。
设计一个算法,求二叉树b中第k层上的叶子结点个数。

#### 答案:
```cpp
typedef struct{
    char data;
    struct *rchild, *lchild;
}BtNode;

int CountKthLevelLeaves(BtNode* root, int k){
  if(k==1){
    if(root->lchild==NULL && root->rchild=NULL) return 1;
    return 0;
  }
  int sum= 0;
  if(root->lchild) sum+= CountKthLevelLeaves(root->lchild, k-1);
  if(root->rchild) sum+= CountKthLevelLeaves(root->rchild, k-1);
  return sum;
}
```

Q17:
假设二叉树中的每个结点值为单个字符,采用二叉链存储结构存储。
设计一个算法,判断值为x的结点与值为y的结点是否互为兄弟,假设这样的结点值是唯一的。

#### 答案:
```cpp
typedef struct{
    char data;
    struct *rchild, *lchild;
}BtNode;

bool IsBrother(BtNode* root, char x, char y) {
  if(root==NULL)return false;
  if(root->lchild && root->rchild){
    auto compare= [x,y](BtNode* left, BtNode* right){
      return (left->data==x && right->data==y) || (left->data==y && right->data==x);
      };
    return compare(root->lchild, root->rchild);
  }

  return IsBrother(root->lchild, x, y) || IsBrother(root->rchild, x, y);
}
//Lambda 表达式定义: auto 函数名=  [捕获列表](参数列表) { 函数体 };
}
Q18:
假设二叉树中的每个结点值为单个字符,采用二叉链存储结构存储。
设计一个算法,采用先序遍历方法求二叉树b中值为x的结点的子孙结点,假设值为x的结点是唯一的。

#### 答案:
```cpp
void Output(BtNode* root){
  if(root==NULL) return;
  printf("%c\t",root->data);
  Output(root->lchild);
  Output(root->rchild);
}

void Find(BtNode* root, char x){
  if(root==NULL) return;
  if(root->data==x){
    Output(root->lchild);
    Output(root->rchild);
    return;
  }

  Find(root->lchild, x);
  Find(root->rchild, x);
}
```

设计一个算法,判断一个字符串s是否为形如"序列1@序列2""模式的字符序列,其中序列1和序列2都不含有 '@' 字符,且序列2是序列1的逆序列。

例如 "a+b@b+a" 属于该模式的字符序列,而 "1+3@3-1"不是。

bool IsTrue(SqString s){
  vector<char> v;
  int i= 0;
  while(i<s.length){
    char e= s.data[i];
    if(e!='@') v.push_back(e);
    else break;
    i++;
  }
  i++;
  while(i<s.length){
    e= s.data[i];
    if(v.size()==0) return false;
    if(v.back()!=e) return false;
    v.pop_back()
    i++;
  }
  if(v.size()!=0) return false;
  return true;
}

采用带头结点的单链表表示链串,每个结点存放一个字符,设计一个算法,将链串s中所有值为x的字符删除,要求算法的时间复杂度为O(n)、空间复杂度为O(1) 。

void DeleteX(LinkString* &s, char x) {
  LinkString *pre= s, *p= pre->next;
  while(p!==NULL){
    if(p->data==x){
      pre->next= p->next;
      free(p);
      p= pre->next;
    }
    else{
      pre= pre->next;
      p= p->next;
    }
  }
}

DFS

假设不带权有向图采用邻接表G存储,设计一个算法,判断其中是否存在经过顶点v的回路(一条回路中至少包含3个不同的顶点)。

int visited[MaxV];
bool Cycle(AdjGraph *G, int u, int v, int d, bool &has){
    ArcNode *p;
    visited[u]= 1;
    d++;
    p= G->adjlist[u].firstarc;
    while(p!=NULL){
        int w= p->adjvex;
        if(visited[w]==0)Cycle(G,w,v,d,has);
        else if(w==v && d>1){
            has= true;
            return;
        }
        p= p->nextarc;
    }
}
bool HasCycle(AdjGraph *G, int v){
    bool has= false;
    Cycle(G,v,v,-1,has);
    return has;
}

DFS

假设无向图G采用邻接表存储,设计一个算法,判断图G是否为一棵树,若为树,返回真;否则返回假。

一个无向图G是树的条件:无向图联通且无回路或无向图联通只有n-1条边

int visited[MaxV];
void DFS(AdjGraph *G, int v, int &vn, int &en){
    ArcNode *p;
    visited[v]= 1; vn++;
    p= G->adjlist[v].firstarc;
    while(p!=NULL){
        en++;
        if(visited[p->adjvex]==0) DFS(G, p->adjvex, vn, en);
        p= p->nextarc;
    }
}
bool IsTree(AdjGraph *G){
    int vn= 0, en= 0;
    for(int i= 0; i<G->n; i++) visited[i]= 0;
    DFS(G,1,vn,en);
    if(vn==G->n && en==2*(G->n-1)) return true;
    else return false;
}

设不带权无向图G采用邻接表表示,设计一个算法求源点i到其余各顶点的最短路径长度。

法一Dijkstra算法,法二广度优先遍历 BFS

int visited[MaxV];
void BFS(AdjGraph *G, int i){
    int qu[MaxV],level[MaxV];
    int front= 0, rear= 0;
    ArcNode *p;
    visited[i]= 1;
    rear++; qu[rear]= i; level[rear]= 0;
    while(front!=rear){
        front= (front+1)%MaxV;
        int k= qu[front];
        int lev= level[front];
        if(k!=i)printf("顶点%d到顶点%d的最短距离是:%d",i,k,lev);
        p= G->adjlist[k].firstarc;
        while(p!=NULL){
            if(visited[p->adjvex]==0){
                visited[p->adjvex]= 1;
                rear= (rear+1)%MaxV;
                qu[rear]= p->adjvex;
                level[rear]= lev+1;
            }
            p= p->nextarc;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值