C语言算法题

(c99之前不支持在for循环括号中定义变量)

1.爬楼梯 (LeetCode70)

int climbStairs(int n){
	if(n<=0) return 0;
	if( n== 1) return 1;
	if( n== 2) return 2;
	
	int res=0;
	int pre=1;
	int prePre=2;
	
	int i; 
	for(i=3; i<=n ;i++){
		res=pre+prePre;
		pre=prePre;
		prePre=res;
	}
	return res;
}

斐波那契数列中:pre=0,prePre=1

2.移动0 (LeetCode283)

void moveZeroes(int* nums, int numsSize){
	if(numsSize==0) return;
	
	int i,j;
	for(i=0,j=0;i<numsSize;i++){
		if(nums[i]!=0){
			nums[j]=nums[i];
			j++;
		}
	}
	
	for(;j<numsSize;j++){
		nums[j]=0;
	}
}

3.找到所有数组中消失的数字(LeetCode448)

int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize){
	if(numsSize<=0) return NULL;
	
	int i;
	for(i=0;i<numsSize;i++){
		int a=(nums[i]-1)%numsSize;
		nums[a] +=numsSize;
	}
	
	int count=0;
	for(i=0;i<numsSize;i++){
		if(nums[i]<=numsSize) count++;
	}

	int * returnNums = (int *)malloc( sizeof(int)*count );
	int j=0;
	for(i=0;i<numsSize;i++){
		if(nums[i]<=numsSize) returnNums[j++]=i+1;
	}
	
	*returnSize=count;
	return returnNums;
}

4.反转链表(LeetCode206)

(有待改进,1.不用申请新内存结点,2.while循环改进)


struct ListNode {
	int val;
    struct ListNode *next;
};


struct ListNode* reverseList(struct ListNode* head){
	if( NULL==head ) return NULL;
	if( NULL==head->next ) return head;
	
	struct ListNode* res = (struct ListNode*) malloc (sizeof(struct ListNode));
	res->next=NULL;
	res->val=-1;
	
	struct ListNode* p = head;
	
	struct ListNode* pNext = p->next;
	struct ListNode* resNext = res->next;
	
	while(NULL!=p && NULL!=p->next){
		p->next=resNext;
		res->next=p;
		resNext=p;
		p=pNext;
		pNext=pNext->next;
	}
	
	p->next=resNext;
	res->next=p;
	
	return res->next;
}

5.合并两个有序链表(LeetCode21)

ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
    if(l1==NULL)
        return l2;
    if(l2==NULL)
        return l1;
    if(l1->val < l2->val){
        l1->next = mergeTwoLists(l1->next,l2);
        return l1;
    }else{
        l2->next = mergeTwoLists(l1,l2->next);
        return l2;
    }
}

6.字符串相加(LeetCode415)

char* addStrings(char* num1, char* num2) {
    int i = strlen(num1) - 1, j = strlen(num2) - 1, add = 0;
    char* ans = (char*)malloc(sizeof(char) * (fmax(i, j) + 3));
    int len = 0;
    while (i >= 0 || j >= 0 || add != 0) {
        int x = i >= 0 ? num1[i] - '0' : 0;
        int y = j >= 0 ? num2[j] - '0' : 0;
        int result = x + y + add;
        ans[len++] = '0' + result % 10;
        add = result / 10;
        i--, j--;
    }
    // 计算完以后的答案需要翻转过来
    for (int i = 0;  i < len/2; i++) {
        int t = ans[i];
        ans[i] = ans[len - i - 1];
        ans[len - i - 1] = t;
    }
    ans[len++] = 0;
    return ans;
}

7.快速排序

void quickSort(int *arr, int low, int high){
    if (low < high){
        int i = low;
        int j = high;
        int k = arr[low];
        
        while (i < j){
            while(i < j && arr[j] >= k) j--;    // 从右向左找第一个小于k的数 
            arr[i] = arr[j];	//此时可能i等于j,因此可能会多执行一步无用的操作
            while(i < j && arr[i] < k) i++;     // 从左向右找第一个大于等于k的数 
            arr[j] = arr[i];
        }
        arr[i] = k;
 
        quickSort(arr, low, i - 1);     // 排序k左边 
        quickSort(arr, i + 1, high);    // 排序k右边 
    }
}

8.二分查找

int binarySearch(int nums[], int size, int target) //nums是数组,size是数组的大小,target是需要查找的值
{
    int left = 0;
    int right = size - 1;	// 定义了target在左闭右闭的区间内,[left, right]
    while (left <= right) {	//当left == right时,区间[left, right]仍然有效
        int middle = left + ((right - left) / 2);//等同于 (left + right) / 2,防止溢出
        if (nums[middle] > target) {
            right = middle - 1;	//target在左区间,所以[left, middle - 1]
        } else if (nums[middle] < target) {
            left = middle + 1;	//target在右区间,所以[middle + 1, right]
        } else {	//既不在左边,也不在右边,那就是找到答案了
            return middle;
        }
    }
    //没有找到目标值
    return -1;
}

9.两数之和(LeetCode1)

由于不方便使用Map,所以先使用快排对数组排序,再for循环遍历,通过二分法查询对应结果。
时间复杂度O(nlogn),空间复杂度O(n)

int* twoSum(int* nums, int numsSize, int target, int* returnSize){
	//复制一个原来的数组,用来排序
	int * sortedNums=(int *) malloc( sizeof(int)*numsSize );
	int k;
	for(k=0;k<numsSize;k++){
		sortedNums[k]=nums[k];
	}
	quickSort(sortedNums,0,numsSize-1);
	
	*returnSize=2;
	int * res=(int *) malloc( sizeof(int)*2 );
	int i;
	for(i=0; i<numsSize; i++){
		//遍历原数组nums,在有序的数组sortedNums去查询目标值
		int flag=binarySearch(sortedNums,numsSize,target-nums[i]);
		if(flag>=0){
			int j;
			//根据有序的数组sortedNums查询到的值在原数组中找到下标
			for(j=0;j<numsSize;j++){
				//返回的值不能是相同的元素(下标)
				if(sortedNums[flag]==nums[j] && i!=j){
					res[0]=i;
					res[1]=j;
					return res;
				}
			}
		}
	}
	return NULL;
}

10.图像压缩(MOOC算法设计与分析-屈婉玲 6.2)

1.黑白图像存储
像素点灰度值 : 0∼255,为8位二进制数
图像的灰度值序列 : { p1, p2, … , pn},pi为第i个像素点灰度值
图像存储:每个像素的灰度值占8位,总计空间为 8n

2.图像变位压缩的概念
变位压缩存储: 将{p1, p2,…,pn}分成 m 段
S1, S2, … , Sm
在这里插入图片描述
同一段的像素占用位数相同,第 t 段有 l[t]个像素,每个占用 b[t]位
段头:记录l[t](8位)和b[t](3位)需要11位
总位数为:b[1]⋅l[1]+b[2]⋅l[2]+… +b[m]⋅l[m]+11m

3.图像压缩问题
约束条件:第 t 段像素个数 l[t] ≤256
第 t 段占用空间:b[t]×l[t] + 11
在这里插入图片描述
问题 :给定像素序列{ p1, p2, …, pn},
确定最优分段,即
在这里插入图片描述
4.实例
灰度值序列:P={10,12,15,255,1,2,1,1,2,2,1,1}
分法1: S1= {10, 12, 15},S2={255}, S3={1, 2, 1, 1, 2, 2, 1, 1}
分法2:S1={10,12,15,255,1,2,1,1,2,2,1,1}
分法3: 分成12组,每组一个数
存储空间:
分法1:11×3+4×3+ 8×1+2×8 = 69
分法2:11×1+8×12 =107
分法3:11×12+4×3+8×1+1×5+2×3=163

#include<iostream>
#include<string>
#define Header 11
#define Lmax 256
#define N 1000
using namespace std;
//全部1序
int p[N+1]; //原序列
int S[N+1]; //前N项最优解
int L[N+1]; //当前分组有几项
int b[N+1]; //每项位数
int FL[N+1]; //有几个分组

//求位数
int length(int p){
    int t = 0;
    while(p > 0){
        t++;
        p /= 2;
    }
    return t;
}

//图像压缩
void compress(int p[], int n){
    int bmax = 0;
    int S[n+1];
    S[0] = 0;
    for(int i = 1; i <= n; i++){
        b[i] = length(p[i]);
        bmax = b[i];
        S[i] = S[i-1] + bmax;
        L[i] = 1;
        for(int j = 2; j <= i && j <= Lmax; j++){
            if(bmax < b[i-j+1]){
                bmax = b[i-j+1];
            }
            if(S[i] > S[i-j]+j*bmax){
                S[i] = S[i-j]+j*bmax;
                L[i] = j;
            }
        }
        S[i] += Header;
    }
    // 
    int count = 0;
    for(int j = n; j > 0;){
        FL[++count] = L[j];
        j = j-L[j];
    }
    for(int i = 1, j = count; i < j; i++, j--){
        int k;
        k = FL[i];
        FL[i] = FL[j];
        FL[j] = k;
    }
    //输出
    cout << "最优解" << S[n] << endl;
    cout << "分割====" << endl;
    int c = 1;
    for(int i = 1; i <= count; i++){
        for(int j = 1; j <= FL[i]; j++){
            cout << p[c++] << " ";
        }
        cout << ",";
    }
}
// 12 10 12 15 255 1 2 1 1 2 2 1 1

int main(){
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> p[i];
    }
    compress(p, n);
    return 0;
}
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值