算法题

94 阅读8分钟

第二周(10.30-11.5)

第一题:

题目来源:www.acwing.com/problem/con…

题目描述:

实现一个双链表,双链表初始为空,支持 5种操作:

  1. 在最左侧插入一个数;
  2. 在最右侧插入一个数;
  3. 将第 k个插入的数删除;
  4. 在第 k 个插入的数左侧插入一个数;
  5. 在第 k个插入的数右侧插入一个数

现在要对该链表进行 M次操作,进行完所有操作后,从左到右输出整个链表。

注意:题目中第 k个插入的数并不是指当前链表的第 k个数。例如操作过程中一共插入了 n个数,则按照插入的时间顺序,这 n 个数依次为:第 1个插入的数,第 2个插入的数,…第 n个插入的数。

输入格式

第一行包含整数 M,表示操作次数。

接下来 M行,每行包含一个操作命令,操作命令可能为以下几种:

  1. L x,表示在链表的最左端插入数 x。
  2. R x,表示在链表的最右端插入数 x。
  3. D k,表示将第 k个插入的数删除。
  4. IL k x,表示在第 k个插入的数左侧插入一个数。
  5. IR k x,表示在第 k个插入的数右侧插入一个数。

输出格式

共一行,将整个链表从左到右输出。

数据范围

1≤M≤100000 所有操作保证合法。

输入样例:

10
R 7
D 1
L 3
IL 2 10
D 3
IL 2 7
L 8
R 9
IL 4 7
IR 2 2

输出样例:

8 7 7 3 2 9

解题思路:

10万数据太庞大,只能用数组模拟双链表来完成,不然频繁分配内存,时间太过复杂。

解题代码:

#include <stdio.h>
#include <string.h>
int l[100003];
int r[100003];
int data[100003];
int idx = 2;
void init() {//初始化
    r[0] = 1; // 左头节点
    l[1] = 0; // 右尾结点
}
void add_l(int x) { // 头插
    data[idx] = x;
    l[idx] = 0;
    r[idx] = r[0];
    l[r[0]] = idx;
    r[0] = idx;
    idx++;
}
void add_r(int x) { // 尾插
    data[idx] = x;
    r[idx] = 1;
    l[idx] = l[1];
    r[l[1]] = idx;
    l[1] = idx;
    idx++;
}
void insert_r(int pos, int x) { // 右插
pos++;
data[idx] = x;
l[idx] = pos;
r[idx] = r[pos];
l[r[pos]] = idx;
r[pos] = idx;
idx++;
}
void insert_l(int pos, int x) { // 左插
    pos++;
    pos = l[pos];
    data[idx] = x;
    l[idx] = pos;
    r[idx] = r[pos];
    l[r[pos]] = idx;
    r[pos] = idx;
    idx++;
}
void del(int k) { // 删除
    k++;
    r[l[k]] = r[k];
    l[r[k]] = l[k];
}
int main() {
    int m;
    scanf("%d", &m);
    getchar();
    init();
    while (m--) {
        char str[1000];
        gets(str);
​
    if (str[0] == 'L') {
        int x;
        sscanf(str, "%*s %d", &x);
        add_l(x);
    }
    else if (str[0] == 'R') {
        int x;
        sscanf(str, "%*s %d", &x);
        add_r(x);
    }
   else if (str[0] == 'D') {
        int x;
        sscanf(str, "%*s %d", &x);
        del(x);
    }
    else if (str[0] == 'I') {
        int x, pos;
        sscanf(str, "%*s %d %d", &pos, &x);
        if (str[1] == 'L') {
            insert_l(pos, x);
        }
        else if (str[1] == 'R') {
            insert_r(pos, x);
        }
    }
}
​
for (int i = r[0]; i != 1; i = r[i]) {
    printf("%d ", data[i]);
}
return 0;
}

第二题:

题目来源:www.acwing.com/problem/con…www.acwing.com/problem/con…www.acwing.com/problem/con….........

题目描述:本题是一个自组题,由5道题组成,分别包含了高精度加法,减法,乘法,除法求整,除法求余以及高精度的小数位数。

高精度加法代码:
#include <stdio.h>
#include <string.h> 
int main(){
    char str1[100001];
    char str2[100001];
    gets(str1);
    gets(str2);
    int a[100000]={0};
    int b[100000]={0};
    int c[100000]={0};
    int la,lb,lc;
    la=strlen(str1);
    lb=strlen(str2);
     int i=0;
     for(i=0;i<la;i++){
        a[la-i]=str1[i]-'0'; 
     }
    for(i=0;i<lb;i++){
       b[lb-i]=str2[i]-'0'; 
    }
    int max=la;
    if(lb>max){
        max=lb;
    }
    for(i=1;i<=max;i++){
    c[i]+=a[i]+b[i];
        c[i+1]=c[i]/10;     
        c[i]%=10;
    }
    if(c[max+1]!=0){
        for(i=max+1;i>=1;i--){
            printf("%d",c[i]);
        }
    }
    else
    for(i=max;i>=1;i--){
        printf("%d",c[i]); 
    }
    return 0;
} 
高精度减法代码:
#include <stdio.h>
#include <string.h>
int i,j,m; 
int main() {
    char  str1[100001] = { 0 };
    char  str2[100001] = { 0 };
    gets(str1);
    gets(str2);
    if (strcmp(str1, str2) == 0) {
        printf("0");
        return 0;
    }
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    int index = 0;
    if (len1 < len2) {
        index = 1;
    }
    else if (len1 == len2) {
        for ( i = 0; i < len1; i++) {
            int k = str1[i]-'0';
            int u = str2[i]-'0';
            if (k < u) {
                index = 1;
                break;
            }
            if(k>u){
                index=0;
                break;
            }
        }
    }
    else
    {
        index = 0;
    }
    int a[100001] = { 0 };
    int b[100001] = { 0 };
    int h = 0;
    for ( i = len1 - 1; i >= 0; i--) {
        int k = str1[i] - '0';
        a[h]=k;
        h++;
    }
    h = 0;
    for ( i = len2 - 1; i >= 0; i--) {
        int k = str2[i] - '0';
        b[h] = k;
        h++;
    }
    if (index == 1) {
        printf("-");
    }
    int ans[100005] = { 0 };
    if(index==0){
    for (i = 0; i < len1; i++) {
        int k = a[i] - b[i];
        ans[i] = k;
        if (k >= 0) {
            continue;
        }
        else
        {
            for ( j = i+1; j < len1; j++) {
                if (a[j] == 0) {
                    continue;
                }
                else {
                    a[j]--;
                    for ( m = i + 1; m < j; m++) {
                        a[m] = 9;
                    }
                    ans[i] += 10;
                    break;
                }
            }
        }
    }
    int l = 1;
    for ( i = len1 - 1; i >= 0; i--) {
        if(ans[i]==0&&l==1){
            continue;
        }       
        else
       {
            l=0;
            printf("%d", ans[i]);}
    }
    }
    if (index == 1) {
        for ( i = 0; i < len2; i++) {
            int k = b[i] - a[i];
            ans[i] = k;
            if (k >= 0) {
                continue;
            }
            else
            {
                for ( j = i + 1; j < len2; j++) {
                    if (b[j] == 0) {
                        continue;
                    }
                    else {
                         b[j]--;
                         for ( m = i + 1; m < j; m++) {
                             b[m] = 9;
                         }
                        ans[i] += 10;
                        break;
                    }
                }
            }
        }
        int l = 1;
        for ( i = len2 - 1; i >= 0; i--) {
        if(ans[i]==0&&l==1){
            continue;
        }       
        else
       {
            l=0;
            printf("%d", ans[i]);}
    }
    }
return 0;
}
高精度乘法代码:
#include <stdio.h>
#include <string.h>
int main() {
    int i,j;
    char str1[100007] = { 0 };
    char str2[100000] = { 0 };
    gets(str1);
    gets(str2);
    if(strcmp(str2,"0")==0){
        printf("0");
        return 0;
    }
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    int a[100007] = { 0 };
    int b[100001] = { 0 };
    int k,h=0;
    for (i = len1 - 1; i >= 0; i--) {
        k = str1[i] - '0';
        a[h] = k;
        h++;
    }
    h = 0;
    for (i = len2 - 1; i >= 0; i--) {
        k = str2[i] - '0';
        b[h] = k;
        h++;
    }
    int ans[100009]={0};
    for (i = 0; i < len2; i++) {
        int g = i;
        for ( j = 0; j <= len1; j++) {
            int k = a[j] * b[i];
            ans[g] += k;
            if (ans[g] >= 10) {
                ans[g + 1] += ans[g] / 10;
                ans[g] %= 10;
            }
            g++;
        }
    }
     j = 1;
    for (i = 100009; i >= 0; i--) {
        if (ans[i] == 0 && j) {
            continue;
        }
        else {
            j = 0;
            printf("%d", ans[i]);
        }
    }
    return 0;
}
高精度除法取整与取余代码:
#include <stdio.h>
#include <string.h>
int main() {
    int b;
    char str[100002] = { 0 };
    gets(str);
    scanf("%d", &b);
    if(strcmp(str,"0")==0){
        printf("0\n0");
        return 0;
    }
    int c[100001] = { 0 };
    int len = strlen(str);
    int a[100001] = { 0 };
    int h = 0;
    for (int i = 0; i < len; i++) {
        int k = str[i] - '0';
        a[h++] = k;
    }
    int k = 0;
    h = 0;
    for (int i = 0; i < len; i++) {
        k += a[i];
        c[h++] = k / b;
        k = k % b*10;
    }
    int g=0;
    for(int i=0;i<len;i++){
        if(c[i]!=0){
            g=1;
            break;
        }
    }
    if(g){
    int l = 1;
    for (int i = 0; i < len; i++) {
        if (c[i] == 0 && l) {
            continue;
        }
        else
        {
            l = 0;
            printf("%d", c[i]);
        }
    }
    printf("\n%d", k/10);}
    else{
        printf("0\n%s",str);
    }
    return 0;
}
除法小数高精度代码:
#include <stdio.h>
#include <string.h>
int main(){
    int a,b;
    scanf("%d %d",&a,&b);
    int c=a/b;
    char str[20000]={0};
    sprintf(str,"%d",c);
    strcat(str,".");
    int n;
    int d=a%b;
    scanf("%d",&n);
    int i;
    for(i=0;i<n;i++){
        int m=(d*10/b);
        char s[2];
        sprintf(s,"%d",m);
        strcat(str,s);
        d=d*10%b;
    }
    printf("%s",str);
return 0;
​
} 

第三题:

题目来源:209. 长度最小的子数组 - 力扣(LeetCode)

题目描述:一种算法,两种题型,分别求长度的最大和最小值。

类一:

给定一个含有 n 个正整数的数组和一个正整数 target
找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度 如果不存在符合条件的子数组,返回 0

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

解题思路:

本题主要运用了滑动窗口算法,如果当前的和小于目标值,则让右指针不断向右移,当大于等于时,进入左指针循环,左指针不断地向右指针靠拢,直到小于目标值,跳出循环,循环外循环,直到又指针碰到边界输出结果。需要注意的是,滑动窗口的遍历,一般用右指针来遍历,同时不断的更新长度,若小于既有的最小值,则更新最小值。

代码如下:

int minSubArrayLen(int target, int* nums, int numsSize) {
   int minlenth=0;
   int i=0;
   int sum=0;
   int l=0,r=0;
   int lenth=0;
   while(r<numsSize){
    sum+=nums[r];
    while(sum>=target){
        lenth=r-l+1;
        if(lenth<minlenth||minlenth==0){
            minlenth=lenth;
           }
           sum-=nums[l];
           l++;
       }    r++;
   }
   return minlenth;
       }
本题需要注意的是,在什么地方计算lenth长度,才能处理边界问题,选择在移动左标的循环中计算长度,既能计算每一次左标右移的结果,又可以处理边界问题,即如果加最后一个元素大于才会进入循环,否则可以不用计算。

类二:

题目描述:

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

解题思路:

用一个阿斯克码数组储存,字符串数组中每个元素出现的位置的下标,并且用了左右两个指针,利用滑动窗口的算法来计算之间的距离。

解题代码:

int lengthOfLongestSubstring(char* s) {
  int n = strlen(s);
  int i = 0, j = 0, max = 0;
  int index[256] = {0};
  while (j < n) {
    if (index[s[j]] > i) {
      i = index[s[j]];
    }
    index[s[j]] = j + 1;
    if (max < j - i + 1) {
      max = j - i + 1;
    }
    j++;
  }
  return max;
}