天天看點

LeetCode每周五道題:1、9、29、136、143。

寫在前面:

LeetCode每周五道題(初階)系列部落格介紹

ps.我為什麼要每周做五道題,那當然是為了讓這個世界上少一個菜雞。

目标:每周刷五道題

題目範圍:不限

題目構成:4+1(四道簡單題目加一道中等題目)

注:後續的題目數量以及難易程度會慢慢調整

題目大綱

  1. 兩數之和(leetcode 題号:1,難度:簡單)
  2. 回文數(leetcode 題号:9,難度:簡單)
  3. 删除有序數組中的重複項(leetcode 題号:29,難度:簡單)
  4. 隻出現一次的數字 (leetcode 題号:136, 難度:簡單)
  5. 重排連結清單 (leetcode 題号:143, 難度:中等)

1.兩數之和 (leetcode 題号:1,難度:簡單)

1.1 題目描述

給定一個整數數組 nums 和一個整數目标值 target,請你在該數組中找出 和為目标值 target 的那 兩個 整數,并傳回它們的數組下标。

你可以假設每種輸入隻會對應一個答案。但是,數組中同一個元素在答案裡不能重複出現。

你可以按任意順序傳回答案。

示例 1:

輸入:nums = [2,7,11,15], target = 9

輸出:[0,1]

解釋:因為 nums[0] + nums[1] == 9 ,傳回 [0, 1] 。

示例 2:

輸入:nums = [3,2,4], target = 6

輸出:[1,2]

示例 3:

輸入:nums = [3,3], target = 6

輸出:[0,1]

1.2 解法:暴力周遊循環

首先在不考慮時間和空間複雜度的情況下,可以直接使用雙循環周遊的方法,從數組的下标0開始,向後周遊,判斷之和等于target時将兩個元素的下标傳回即可。

代碼示例:

class Solution {
public:
	vector<int> twoSum(vector<int>& nums, int target) {
		int i = 0;
		int len = nums.size();
		vector<int> vctResult;
		for (i = 0; i < len; i++)//雙層周遊即可,目前元素自身不需要和自己比較
		{
			int j = 0;
			if (i + 1 == len)
			{
				break;
			}
			for (j = i + 1; j < len; j++)
			{
				if ((nums[i] + nums[j]) == target)
				{
					vctResult.push_back(i);
					vctResult.push_back(j);
				}
			}
		}
		return vctResult;
	}
};
           

執行結果:

LeetCode每周五道題:1、9、29、136、143。

2.回文數(leetcode 題号:9,難度:簡單)

2.1 題目描述

給你一個整數 x ,如果 x 是一個回文整數,傳回 true ;否則,傳回 false 。

回文數是指正序(從左向右)和倒序(從右向左)讀都是一樣的整數。例如,121 是回文,而 123 不是。

示例 1:

輸入:x = 121

輸出:true

示例 2:

輸入:x = -121

輸出:false

解釋:從左向右讀, 為 -121 。 從右向左讀, 為 121- 。是以它不是一個回文數。

示例 3:

輸入:x = 10

輸出:false

解釋:從右向左讀, 為 01 。是以它不是一個回文數。

示例 4:

輸入:x = -101

輸出:false

2.2 解法:先将整數的 [個十百千…位] 上的數字取出來,存入vector中然後進行前後逐個比較即可

代碼示例:

class Solution{
public:
	bool isPalindrome(int x) {
		vector<int> v;
		if (x < 0)//負數直接傳回False
		{
			return false;
		}
		if ((x>=0)&&(x<10))//個位數直接傳回true
		{
			return true;
		}
		while (x > 0)//取出來每個位置的數字
		{
			int temp = x % 10;
			x /= 10;
			v.push_back(temp);
		}
		int k = 0;
		int end = v.size()-1;
		for (k = 0; k < v.size()/2; k++)//首尾逐個進行比較
		{
			if (v[k] != v[end])
			{
				return false;
			}
			end--;
		}
		return true;
	}
};
           

執行結果:

LeetCode每周五道題:1、9、29、136、143。

3.删除有序數組中的重複項(leetcode 題号:29,難度:簡單)

3.1 題目描述

給你一個有序數組 nums(升序) ,請你 原地 删除重複出現的元素,使 每個元素 隻出現一次 ,傳回删除後數組的新長度。

題目解析,這裡是傳引用的方式進行傳參,意思是需要在原數組上進行修改,删除多餘的元素,傳回一個數組的長度,leetcode背景會根據你傳的數組的長度對數組進行取元素,例如長度為1,就選取數組中的第一個元素(下标為0),然後用測試用例的結果進行比對,判斷是否通過測試用例。

不要使用額外的數組空間,你必須在 原地 修改輸入數組 并在使用 O(1) 額外空間的條件下完成。

不允許申請新的空間,隻可以在原數組修改

示例 1:

輸入:nums = [1,1,2]

輸出:2, nums = [1,2]

解釋:函數應該傳回新的長度 2 ,并且原數組 nums 的前兩個元素被修改為 1, 2 。不需要考慮數組中超出新長度後面的元素。

示例 2:

輸入:nums = [0,0,1,1,1,2,2,3,3,4]

輸出:5, nums = [0,1,2,3,4]

解釋:函數應該傳回新的長度 5 , 并且原數組 nums 的前五個元素被修改為 0, 1, 2, 3, 4 。不需要考慮數組中超出新長度後面的元素。

3.2 解法:使用雙下标循環法,将不同的元素依次放在數組的[0,1,2,…]下标處的位置即可。

LeetCode每周五道題:1、9、29、136、143。

代碼示例:

class Solution {
public:
	int removeDuplicates(vector<int>& nums) {
		int k = 0;
		int temp = k + 1;
		int count = 1;
		if (nums.size()==1||nums.size()==0)//特殊值處理
		{
			return nums.size();
		}
		while (k < nums.size())
		{
			while (nums[k] == nums[temp])
			{
				if (temp == nums.size() - 1)//當已經走到最後一個元素直接傳回
				{
					return count;
				}
				if (temp + 1 != nums.size())//注意越界
				{
					temp++;
				}
			}
			if (nums[k] != nums[temp])//找到不重複的元素
			{
				nums[k + 1] = nums[temp];//指派
				count++;//計數
				if (temp == nums.size() - 1)
				{
					return count;
				}
				else
				{
					k++;
                    temp++;//下标繼續向後移動
				}
			}
		}
        return count;
	}
};
           

執行結果:

LeetCode每周五道題:1、9、29、136、143。

注意的點:

1.首先要注意數組的越界通路問題,因為有兩個數組下标,且兩個下标是互動的進行跳躍的,是以很容易出現越界的情況.

2.還要注意以下邊界值的情況,考慮數組為空的情況,且對一些特殊的數組,例如隻有一個元素的數組直接傳回1即可。

LeetCode每周五道題:1、9、29、136、143。

4.隻出現一次的數字 (leetcode 題号:136, 難度:簡單)

4.1 題目描述

給定一個非空整數數組,除了某個元素隻出現一次以外,其餘每個元素均出現兩次。找出那個隻出現了一次的元素。

說明:

你的算法應該具有線性時間複雜度。 你可以不使用額外空間來實作嗎?

示例 1:

輸入: [2,2,1]

輸出: 1

示例 2:

輸入: [4,1,2,1,2]

輸出: 4

4.2 解法:按位異或

因為隻有一個元素是不重複的,其他的元素都是兩個兩個相同的,根據按位異或的知識可以知道,兩個相同的元素按位異或為0,而任何一個數與0異或都是這個數本身。

代碼示例:

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int i = 0;
		for (i = 1; i < nums.size(); i++)
		{
			nums[0] ^= nums[i];
		}
		return nums[0];
    }
};
           

執行結果:

LeetCode每周五道題:1、9、29、136、143。

5.重排連結清單 (leetcode 題号:143, 難度:中等)

5.1題目描述

給定一個單連結清單 L 的頭節點 head ,單連結清單 L 表示為:

L0 → L1 → … → Ln-1 → Ln

請将其重新排列後變為:

L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → …

不能隻是單純的改變節點内部的值,而是需要實際的進行節點交換。

示例1:

LeetCode每周五道題:1、9、29、136、143。

輸入: head = [1,2,3,4]

輸出: [1,4,2,3]

示例2:

LeetCode每周五道題:1、9、29、136、143。

輸入: head = [1,2,3,4,5]

輸出: [1,5,2,4,3]

5.2 解法:

首先需要明白這個是要進行結點插入,将倒數第一個結點插入到第一個結點之後,将倒數第二個結點插入到第二個結點的後面(更準确的來說是第三個結點的後面,因為前面已經插入了一個結點)

那麼整體的思路就是:

1.依次找到最後一個結點,将這個結點儲存下來,用于後面的插入。

LeetCode每周五道題:1、9、29、136、143。

2.将結點在正确的結點後面進行插入

LeetCode每周五道題:1、9、29、136、143。

代碼示例:

class Solution {
public:
    void reorderList(ListNode* head) {
        if(head->next == nullptr||head->next->next==nullptr )//對隻有一個結點或者兩個結點的情況進行處理
        {
            //不做任何處理
        }
        else
        {
        ListNode* curNode = head;//記錄目前節點的位置
        while((curNode->next!=nullptr)&&(curNode->next->next)!=nullptr)//插入結點的結束條件并且判空
        {
                ListNode* pNext = head;
                ListNode* pLast = nullptr;
                while(pNext->next->next!=nullptr)//找到尾結點的前一個結點
                {
                    pNext = pNext->next;
                }
                pLast = pNext->next;//最後一個節點
                pNext->next = nullptr;//将倒數第二個結點的next置為nullptr
                ListNode* tempNode = curNode->next;//儲存插入節點的下一個結點
                curNode->next = pLast;//插入并連結前後結點
                pLast->next = tempNode;
                curNode = tempNode;//設定下一次插入的位置(後插入)
        }
        }
    }
};
           

執行結果:

LeetCode每周五道題:1、9、29、136、143。

注意的點:

1.首先這道題需要理清解題的思路,即插入的結點是什麼,插入的位置是什麼,什麼時候結束插入。

2.注意邊界值的判斷,并且注意尾結點的next的置空,對結點的判空,否則就會出現崩潰,非法通路,導緻不能通過所有的測試用例。

本地測試代碼:

#include<vector>
#include<iostream>
using namespace std;
//1.兩數之和(leetcode 題号:1)
class Solution1 {  
public:
	vector<int> twoSum(vector<int>& nums, int target) {
		int i = 0;
		int len = nums.size();
		vector<int> vctResult;
		for (i = 0; i < len; i++)//暴力雙循環
		{
			int temp = 0;
			int j = 0;
			if (i + 1 == len)
			{
				break;
			}
			for (j = i + 1; j < len; j++)
			{	
				if ((nums[i] + nums[j]) == target)
				{
					vctResult.push_back(i);
					vctResult.push_back(j);
				}
			}
		}
		return vctResult;
	}
};
//2.回文數(leetcode 題号:9)
class Solution2 {
public:
	bool isPalindrome(int x) {
		vector<int> v;
		if (x < 0)//負數直接傳回false
		{
			return false;
		}
		if ((x >= 0) && (x < 10))//個位數直接傳回true
		{
			return true;
		}
		while (x > 0)
		{
			int temp = x % 10;//先取個位數,再取百位,千位....依次類推
			x /= 10;
			v.push_back(temp);
		}
		int k = 0;
		int end = v.size()-1;
		for (k = 0; k < v.size()/2; k++)//從頭部和尾部依次開始比較
		{
			if (v[k] != v[end])
			{
				return false;
			}
			end--;
		}
		//int j = 0;
		//for (j = 0; j < v.size(); j++)
		//{
		//	cout << v[j] << " " << endl;
		//}
		return true;
	}
};
void PrintResult(vector<int> vct)//列印數組元素函數
{
	int j = 0;
	for (j = 0; j < vct.size(); j++)
	{
		cout << vct[j] << " " << endl;
	}
}
//3.删除有序數組中的重複項(leetcode 題号:29)
class Solution3 {
public:
	int removeDuplicates(vector<int>& nums) {
		int k = 0;
		int temp = k + 1;//這個變量是一直存在的 而不是每次循環位置被重新改變
		int count = 1;
		if (nums.size()==1||nums.size()==0)//判斷邊界值或者隻有一個元素的情況
		{
			return nums.size();
		}
		while (k < nums.size())
		{
			while (nums[k] == nums[temp])
			{
				if (temp == nums.size() - 1)//周遊到了最後一個元素 
				{
					return count;
				}
				if (temp + 1 != nums.size())
				{
					temp++;//遇到相同元素位置++
				}
			}
			if (nums[k] != nums[temp])//找到不重複的元素
			{
				nums[k + 1] = nums[temp];//指派
				temp++;
				count++;//計數器++
				if (temp == nums.size() - 1)
				{
					return count;
				}
				else
				{
					k++;//下一個開始比較的位置
				}
			}
		}
		return count;
	}
};
//4.隻出現一次的數字 (leetcode 題号 136)
class Solution4 {
public:
	int singleNumber(vector<int>& nums) {
		int i = 0;
		for (i = 1; i < nums.size(); i++)
		{
			nums[0] ^= nums[i];
		}
		return nums[0];
	}
};
int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(1);
	//v.push_back(1);
	v.push_back(2);
	v.push_back(2);
	//v.push_back(2);
	v.push_back(3);
	//Solution1 s;
	//s.twoSum(v, 6);
	//PrintResult(s.twoSum(v, 6));
	//Solution2 s2;
	//s2.isPalindrome(121);
	//Solution3 s3;
	//cout << s3.removeDuplicates(v) << endl;
	Solution4 s4;
	cout<<s4.singleNumber(v);

	return 0;
}