剑指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;
    }
};

效率更高的做法
我们要统计字符的次数,每个字符对应存在其出现次数,如果采用KV结构来统计,O(n)O(n)的复杂度就可以实现。

class Solution {
public:
	int FirstNotRepeatingChar(string str) {
	unordered_map<char, int> mymap;
	int The_Once = 0;
	for (int i = 0; i < str.size(); ++i) 
    {
        ++mymap[str[i]];//统计字符出现次数,
        //如果之前map中没有str[i]作为key的键值对,这一操作实现插入和++
        //统计同时去判断str出现字符出现次数是否>1,如果>1,肯定不是第一次出现,下标++
		while(mymap[str[The_Once]] > 1 && The_Once < str.size()) 
			++The_Once;
	}
	return The_Once == str.size() ? -1 : The_Once;
}
};

牛客网链接

数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数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(n2)O(n^2)的直接遍历法,可是这样的效率确实是低,都通不过OJ测试。

归并排序:
剑指offer(34~36)第一个只出现一次的字符--数组中的逆序对--找两个链表的公共结点
统计逆序对的过程:统计逆序次数在(c)(d)过程中,简要分析一下(d)过程,因为已经有序,所以如果,data[left]<data[right],那么以data[left]为逆序对的首元素的逆序对不存在,此时data[left]是两个数组中最小的数,将其放置到辅助数组copy内,否则,data[right]为两个数组最小值,以data[right]为逆序对的尾元素存在逆序对个数等于mid-left+1个。
剑指offer(34~36)第一个只出现一次的字符--数组中的逆序对--找两个链表的公共结点

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);
		}
	}
};

牛客网链接

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

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

  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;
    }
};

牛客网链接