LeetCode 1-5

1 Two Sum - input array is stored

题目描述:

在一个”增序“的整数数组里找到两个数,使它们的和为定值。已知有且只有一对解。

输入输出样例:

输入是一个数组numbers和一个定值target,输出是两个数的位置下标,从0开始计数。

Input: numbers = [2,7,11,15], target = 9;
Output: [0,1]

Input:  nums = [3, 2, 4], target = 6
Output: [1,2]

题解:

首先输入为乱序数组;输出为数组序列号从0开始。

解题方法:

1 一遍哈希法

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> num_map;                   //建立哈希表

        for (int i = 0; i < nums.size(); i++){
            auto it = num_map.find(target - nums[i]);      //寻找配对元素

            if (it != num_map.end()){                      //假设数组中不存在重复元素
                return vector<int>{ it->second, i };       //返回配对数的下标和原数的下标
            }
            num_map[nums[i]] = i;                          //哈希表中的存储情况
        }

        return vector<int>();        
    }
};

此处用到了map语法,由于笔者对老本行已经忘记的差不多了,下面对map知识进行补充。

1 map是STL的一个关联容器,提供一对一的数据处理能力。其内部自建一棵红黑树,这个树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的。

2  map的构造函数

map<int, string> mapStudent;

   在构造map容器后,插入数据 之 insert--Pair数据 

        map<int, string> mapStudent;

        mapStudent.insert(pair<int, string>(1,"student_one"));

        mapStudent.insert(pair<int, string>(2, "student_two"));

        map<int, string>::iterator iter;

        for(iter=mapStudent.begin(); iter!=mapStudent.end(); iter++){

//iter->first会得到关键字,iter->second会得到值。

                cout<<iter->first<<" "<<iter->second<<endl;

        } 

2 两遍哈希表

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> num_map;        //定义无序哈希表
        
        for (int i = 0; i < nums.size(); i++){
            num_map[nums[i]] = i;               
//将数组存入哈希表中,其中num_map关键字里面的值为数组中元素值,其值为数组下标
        }
        
        for (int i = 0; i < nums.size(); i++){
            auto it = num_map.find(target - nums[i]);        //为数组中元素寻找配对
            
            // 此处注意不要遗漏去重判断,两者不能为同一个数
            if (it != num_map.end() && it->second != i){
                return vector<int>{ i, it->second };         //返回下标
            }
        }
        
        return vector<int>();
    }
};

2 Add Two Numbers

题目

给出两个非空链表用于表示两个非负的整数,其中它们各自的位数是按照逆序的方式存储的,并且它们的每个节点都只能存储一位数字。将两个数相加,会返回一个新的链表表示两数之和。

e.g. 
Input: (2->4->3)+(5->6->4)
Output: 7->0->8
342+465=807 

解法

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* ans = new ListNode(0);
        ListNode* ansPosi = ans;
        bool addOne; //也可用整数{0,1}表示,经测试效果相同
        while (l1 != NULL || l2 != NULL || addOne) {
            //取出该位数值
            int num1 = 0, num2 = 0;
            if (l1 != NULL) {
                num1 = l1 -> val;
                l1 = l1 -> next;
            }
            if (l2 != NULL) {
                num2 = l2 -> val;
                l2 = l2 -> next;
            }
            
            //相加、进位
            int sum = num1 + num2;
            if (addOne) sum++;
            addOne = false;
            if (sum > 9) {
                addOne = true;
                sum = sum - 10;
            }
            
            // 写入答案链表
            ListNode *nextPosi = new ListNode(sum);
            ansPosi -> next = nextPosi;
            ansPosi = ansPosi -> next;
        }
        return ans -> next; //考虑代码简洁性,从答案链表第二位开始写入,因此返回第二位
        
    }
};

3 Longest Substring Without Repeating Characters

对于最长无重复子串,较为不错的方法为 滑动窗口 法,其步骤描述如下:

① i,j分别代表窗口左右边界,最大不重复子串的值就是这个窗口能达到的值;

② 判断j++处的字符是否在窗口中,若无就加入窗口再后移。

③随着j的增加,在窗口中有重复的值,然后开始i++,直至窗口内无重复元素;

④ 重复以上步骤,直至j到头为止,而后返回窗口内元素总数。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        set <char> t;                        //子集t代表滑动窗口
                                             //left,right分别代表窗口的左右下标,均从0开始
        int res=0, left =0, right=0;    
        while(right<s.size()){
            if(t.find(s[right])==t.end()){    //滑动窗口的最后一个元素添加到set t中
                t.insert(s[right++]);
                res= max(res,(int)t.size());  //res表示滑动窗口大小
            }else{                            //遇到重复值
                t.erase(s[left++]);            //重复值除去最先添加的在左边的值
            }
        }
        return res;
    }
};

4 Median of Two Sorted Arrays

功能:返回两个有序字符串的中位数。

方法:用一个新的数组存放num1和num2合并后的数组,再取其中位数。

class Solution{
public:
	double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2){
		vector<int> numsAll;		//用来存放合并后的两个数组的新数组
		
		m=nums1.size();
		n=nums2.size();
		for (int i=0,j=0; i< m()||j< n();){
			if(i<m){
				if(j<n){
					if(nums1[i]<nums2[j]){
						numsAll.push_back(nums1[i++]);	//小的放前面
					}else{
						numsAll.push_back(nums2[j++]);
					}
				}else{
					numsAll.push_back(nums1[i++]);
				}
			}else{
				numsAll.push_back(nums2[j++])
			}
		}
		int middle = (nums1.size()+nums2.size())>>1;	//右移一位
		if((nums1.size()+nums2.size())%2 == 1){
			return (double)numsAll[middle];
		}else{
			return ((double)numsAll[middle]+(double)numsAll[middle-1])/2.0;
		}
	}
};

5 Longest Palindromic Substring最长回文子串

法1 : 中心扩展法

① 回文子串长度为奇数,往两边扩展,假设中心字符下标为i,只要有下标为i-1, i+1的两个字符串相等,那么回文子串的长度加2,继续向两边扩展,直到找到两个相同字符串或者到达原字符串边界时停止。

② 回文子串长度为偶数,对比i及i+1,如果二者不同,继续向外扩展,直到相同或超出字符串边界为止。

这种方法过于麻烦,改了一位bloger的代码发现出现Time Limit Exceeded.超时了!而且总耗时大,请直接跳到法2 manacher.

法2: Manacher法

① 字符串预处理

在开头结尾以及每个字符两边均加上“#”,使得n长的数组变成3n大小。以减少处理偶数子串的麻烦;

② 从左到右依次处理每个字符;

③ 对每个字符,先判断它是否位于某个回文串内,如果是,则以它为中心的串的长度至少为到其对称位置上的长度,如果不是,则继续依次搜索。并在搜索过程中记录当前发现最长串的位置。法1耗时26ms, 法2耗时8ms. 

class Solution{
public:
	string processString(const string &s){
		string str = "^#";
		for (int i=0;i<s.size();i++){
			str+=s[i];
			str+="#";
		}
		str+="$";
		return str;
	}
	string longestPalindrome(string s){
		string str = processString(s);
		int ans = 0;		//结果串的长度
		int ans_pos = 0;	//结果串的中心
		int id=0;			//搜索最远回文串的中心
		int mx=0;
		vector<int> p(str.size(),0);
		for(int i=1;i<str.size()-1;i++){
			//如果前面已经遍历过,则直接和对称位置比较
			p[i]=mx>i?min(p[2*id-i],mx-i):1;
			
			while(str[i+p[i]]==str[i-p[i]])p[i]++;
			
			if(i+p[i]>mx){
				mx=i+p[i];
				id=i;
			}
			
			if(p[i]>ans){
				ans=p[i];
				ans_pos=i;
			}
		}
		return s.substr((ans_pos-ans)/2,ans-1);
	}
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小菜鸡变形记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值