剑指offer(34~36)第一个只出现一次的字符--数组中的逆序对--找两个链表的公共结点

第一个只出现一次的字符

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).

笨方法

无论你有多少字符,所有字符都会有对应的ASCLL码值,在0~255区间。所以我开辟一个255的数组大小,元素初始值都为0,遍历字符串,将字符的ASCLL码值对应下标的值++,用来统计该字符的次数。

class Solution {
public:
    int FirstNotRepeatingChar(string str) {
        int hash[256]={0};
        for(int i=0;i<str.size();i++)
            hash[str[i]]++;
        
        for(int i=0;i<str.size();i++)
        {
            if(hash[str[i]]==1)
                return i;
        }
        return -1;
    }
};

牛客网链接

数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

输入描述:
题目保证输入的数组中没有的相同的数字
数据范围:

对于%50的数据,size<=10^4

对于%75的数据,size<=10^5

对于%100的数据,size<=2*10^5

示例1
输入:1,2,3,4,5,6,7,0
输出:7

思路分析:归并排序在合并有序数组的同时统计逆序对数
看到这道题,我也想到 O ( n 2 ) O(n^2) O(n2)的直接遍历法,可是这样的效率确实是低,都通不过OJ测试。

归并排序:
在这里插入图片描述
统计逆序对的过程:统计逆序次数在(c)(d)过程中,简要分析一下(d)过程,因为已经有序,所以如果,data[left]<data[right],那么以data[left]为逆序对的首元素的逆序对不存在,此时data[left]是两个数组中最小的数,将其放置到辅助数组copy内,否则,data[right]为两个数组最小值,以data[right]为逆序对的尾元素存在逆序对个数等于mid-left+1个。
在这里插入图片描述

class Solution {
public:
	long long nums = 0;
	int InversePairs(vector<int> data) {
		vector<int> copy = data;
		MSort(data, copy, 0, data.size() - 1);
		return nums % 1000000007;
	}

	void Merge(vector<int> &data, vector<int> &copy, int begin, int mid, int end)
	{
		int start = begin;//记录开始位置
		int left = begin;
		int right = mid + 1;
		while (left <= mid && right <= end)
		{
			if (data[left] < data[right])
			{
				copy[begin++] = data[left++];
			}
			else
			{
				copy[begin++] = data[right++];
				nums += mid - left + 1;
			}
		}
		while (left <= mid)
		{
			copy[begin++] = data[left++];
		}
		while (right <= end)
		{
			copy[begin++] = data[right++];
		}
		while (start <= end)//让两个数组数据保持一致
		{
			data[start] = copy[start];
			start++;
		}
	}

	void MSort(vector<int> &data, vector<int> &copy, int begin, int end)
	{
		int mid;
		if (begin < end)
		{
			mid = (begin + end) / 2;
			MSort(data, copy, begin, mid);
			MSort(data, copy, mid + 1, end);
			Merge(data, copy, begin, mid, end);
		}
	}
};

牛客网链接

输入两个链表,找出它们的第一个公共结点。

输入两个链表,找出它们的第一个公共结点。
在这里插入图片描述

  1. 计算两个链表的长度差sub,让较长的链表先走sub个节点。
  2. 然后两个链表同时向后走,直到找到重合的节点。
/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        ListNode* p1=pHead1;
        ListNode* p2=pHead2;
        int len1=0,len2=0;
        while(p1)
        {
            len1++;
            p1=p1->next;
        }
        while(p2)
        {
            p2=p2->next;
            len2++;
        }
        int sub=abs(len1-len2);
        if(len1>len2)
        {
            while(sub)
            {
                pHead1=pHead1->next;
                sub--;
            }
        }
        else
        {
            while(sub)
            {
                pHead2=pHead2->next;
                sub--;
            }
        }
        while(pHead1)
        {
            if(pHead1==pHead2)
                return pHead1;
            pHead1=pHead1->next;
            pHead2=pHead2->next;
        }
        return nullptr;
    }
};

牛客网链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值