目标一周刷2道题
也不知道能坚持几天,这玩意在leetcode做完怎么保存啊
给一个有序的数组,数组中有重复数字,输入一个无序没有重复的数组
百度的一个面试题,被无序搞懵逼了,哎
class Solution {
func test(_ nums: [Int]) -> [Int] {
var result:[Int] = []
var index = 0
while index<nums.count {
result.append(nums[index])
index = index + 1
while index<nums.count && nums[index] == nums[index-1] {
index = index + 1
}
}
index = 0
let randomNumber:Int = Int(arc4random()) % result.count + 1
var t:Int = result[index]
while index + randomNumber < result.count {
t = result[index]
result[index] = result[index + randomNumber]
result[index + randomNumber] = t
index = index + randomNumber
}
return result
}
}
136. 只出现一次的数字
任何数和 0 做异或运算,结果仍然是原来的数,即 a^0=a。
任何数和其自身做异或运算,结果是 0,即 a^a=0。
异或运算满足交换律和结合律,即 aba=baa=b(aa)=b⊕0=b。
/*
[4,1,2,1,2]
4 ^ 1 ^ 1 ^ 2 ^ 2
4 0 0
4
*/
class Solution {
func singleNumber(_ nums: [Int]) -> Int {
var result = 0
for num in nums {
result ^= num
print(result)
}
return result
}
}
70. 爬楼梯
经典动态规划题目
第一级台阶: 1种方法(爬一级)
第二级台阶: 2种方法(爬一级或爬二级)
第三级台阶: 从第一级再爬两级或者从第二级再爬一级 所以是1+2 3种方法
第四级台阶: 从第二级再爬两级或者从第三级再爬一级 所以是2+3 5种方法
第n级台阶:从第n-1爬1级或从第n-2爬2级
递推公式:Fn = Fn-1 + Fn-2
爬到每一级的方法看做一个状态
class Solution {
func climbStairs(_ n: Int) -> Int {
if n < 3 {
return n
}
//记录n个状态,从1到n一次更新
var dp = [0,1,2]
for i in 3...n {
dp.append(dp[i-1] + dp[i-2])
}
return dp[n]
}
}
递归法
子问题 n=1 n=2
class Solution {
func climbStairs(_ n: Int) -> Int {
if n == 1 {
return 1
}
if n == 2 {
return 2
}
return climbStairs(n-1) + climbStairs(n-2)
}
}
66. 加一
数字加法从最后一位开始,倒叙遍历
不是9,直接加1,不用进位
如果是9,变为0,向前遍历+1,直接return
如果遍历完,没有+1,证明全是9,首位补0
class Solution {
func plusOne(_ digits: [Int]) -> [Int] {
var digits = digits
var index = digits.count - 1
while index >= 0 {
if digits[index] == 9 {
digits[index] = 0
index = index - 1
}else{
digits[index] = digits[index] + 1
return digits
}
}
digits.insert(1, at: 0)
return digits
}
}
35. 搜索插入位置
二分查找
关键字:有序,知道范围,待查找的数是整数
插入的位置pos,成立条件 nums[pos-1]<target<=nums[pos]
问题转化为在一个有序数组中找第一个大于等于target的下标
class Solution {
func searchInsert(_ nums: [Int], _ target: Int) -> Int {
var left = 0
var right = nums.count - 1
var result = nums.count
while left <= right {
let mid = (right - left)/2 + left
if nums[mid] == target {
return mid
}else if nums[mid] < target {
left = mid + 1
}else{
right = mid - 1
result = mid
}
}
return result
}
}
26. 删除有序数组中的重复项
双指针
-关键字:原地修改
-模式识别:需要保存可覆盖位置和观测位置,利用双指针
i慢指针,指向答案位置
j快指针,用来扫描
当nums[j] != nums[I],找不到重复项,复制到i的位置,i向前
class Solution {
//[1,1,3,4]
//[1,3,3,4]
//[1,3,4,4]
// 相同 r+1 不同 做一次赋值 r+1 l+1
func removeDuplicates(_ nums: inout [Int]) -> Int {
if(nums.count<2){
return nums.count
}
var left = 1
var right = 1
while right<nums.count {
if nums[right-1] != nums[right]{
nums[left] = nums[right]
left+=1
}
right+=1
}
return left
}
}
20. 有效的括号
栈
先出现的左括号后匹配
模式识别:先进后出用栈
class Solution {
func isValid(_ s: String) -> Bool {
var stack:[Character] = []
for char in s {
if let t_char = stack.last,let c_char = change(char: char),t_char == c_char{
stack.removeLast()
}else{
stack.append(char)
}
}
return stack.count==0 ? true : false
}
func change(char:Character) -> Character? {
switch char {
case ")":
return "("
case "]":
return "["
case "}":
return "{"
default:
return nil
}
}
}
15. 三数之和
排序+双指针
双指针发
- 关键字: 不可以包含重复
- 模式识别: 利用排序避免重复答案
- 降低复杂度变成 两数之和
- 利用双指针找到所有的解,两个指针指向收尾,两数之和小于目标值,头向后移动,使得和增大 ,反之
class Solution {
func threeSum(_ num: [Int]) -> [[Int]] {
var result:[[Int]] = []
var num = num
num.sort()
for (index,n) in num.enumerated() {
//从小到大搜索,跳过重复值
if index>0 && num[index] == num[index - 1] {
continue
}
var left = index + 1
var right = num.count - 1
//三数之和 变为两数之和
while left < right {
let sum = n + num[left] + num[right]
if sum > 0 {
repeat {
right = right - 1
}while right > 0 && right < num.count && num[right] == num[right + 1]
}else{
if sum == 0 {
result.append([n,num[left],num[right]])
}
repeat {
left = left + 1
}while left > 0 && left < num.count && num[left] == num[left - 1]
}
}
}
return result
}
}
13. 罗马数字转整数
class Solution {
func romanToInt(_ s: String) -> Int {
var str = s.replacingOccurrences(of: "CM", with: "a")
str = str.replacingOccurrences(of: "CD", with: "b")
str = str.replacingOccurrences(of: "XC", with: "c")
str = str.replacingOccurrences(of: "XL", with: "d")
str = str.replacingOccurrences(of: "IX", with: "e")
str = str.replacingOccurrences(of: "IV", with: "f")
let charArr:[Character] = Array(str)
var index = charArr.count - 1
var result = 0
while index >= 0 {
result = result + getVaule(char: charArr[index])
index = index - 1
}
return result;
}
func getVaule(char:Character) -> Int {
switch char {
case "M":
return 1000
case "a":
return 900
case "D":
return 500
case "b":
return 400
case "C":
return 100
case "c":
return 90
case "L":
return 50
case "d":
return 40
case "X":
return 10
case "e":
return 9
case "V":
return 5
case "f":
return 4
case "I":
return 1
default:
return -1
}
}
}
12. 整数转罗马数字
class Solution {
func intToRoman(_ num: Int) -> String {
let numArr = [1000,900,500,400,100,90,50,40,10,9,5,4,1]
let luomaArr = ["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"]
var result = ""
var t_index = 0
var t_num = num
while t_index < numArr.count {
for index in t_index...(numArr.count-1) {
if t_num >= numArr[index] {
result = result + luomaArr[index]
t_num = t_num - numArr[index]
break
}else{
t_index = t_index + 1
}
}
}
return result
}
}
11. 盛最多水的容器
class Solution {
func maxArea(_ height: [Int]) -> Int {
guard height.count > 1 else {
return height.first ?? 0
}
var left = 0
var right = height.count
var result = 0
while left != right {
let t_result = min(height[left], height[right-1]) * (right-left - 1)
if height[left] < height[right-1] {
left = left + 1
}else{
right = right - 1
}
if t_result > result{
result = t_result
}
}
return result
}
}
9. 回文数
class Solution {
func isPalindrome(_ x: Int) -> Bool {
if x>=0 && x<10 {
return true
}
if x < 0 || x % 10 == 0{
return false
}
var leftNumber = x
var rightNumber = 0
while !(leftNumber < rightNumber || leftNumber == rightNumber) {
rightNumber = rightNumber * 10 + leftNumber%10
leftNumber = leftNumber/10
}
return leftNumber == rightNumber || leftNumber == rightNumber/10
}
}
7. 整数反转
class Solution {
func reverse(_ x: Int) -> Int {
var x:Int32 = Int32(x)
var rev:Int32 = 0
while x != 0 {
let pushInt = push(x)
if (x > 0 && rev > (Int32.max - pushInt)/10) || (x < 0 && rev < (Int32.max * -1 - pushInt)/10) {
rev = 0
}
else{
rev = rev * 10 + pushInt
}
x = pop(x)
}
//
// rev * 10 + pushInt > Int32.max * -1
return Int(rev)
}
func pop(_ x:Int32) -> Int32 {
return x/10
}
func push(_ x:Int32) -> Int32 {
return x%10
}
}
将有序数组[1,3,5,7,9]和[2,4,6,8,10]合并为一个[1,2,3,4,5,6,7,8,9,10]
class Solution {
func orderListMerage(_ list:[Int],_ list2:[Int]) -> [Int] {
var index1 = 0
var index2 = 0
var result:[Int] = []
while index1 < list.count && index2 < list2.count {
if list[index1] < list2[index2] {
result.append(list[index1])
index1 += 1
}else if list[index1] > list2[index2] {
result.append(list2[index2])
index2 += 1
}else{
result.append(list[index1])
index1 += 1
result.append(list2[index2])
index2 += 1
}
}
while index1 < list.count{
result.append(list[index1])
index1 += 1
}
while index2 < list2.count{
result.append(list2[index2])
index2 += 1
}
return result
}
}
6. Z 字形变换
class Solution {
func convert(_ s: String, _ numRows: Int) -> String {
guard numRows>1 else { return s }
var rows:[[Character]] = []
for _ in 0..<min(numRows, s.count) {
rows.append([Character]())
}
var curRow = 0
var down = false
for (char) in s {
rows[curRow].append(char)
if (curRow == 0 || curRow == numRows - 1){
down = !down
}
curRow = down ? curRow + 1 : curRow - 1
}
var result:[Character] = []
for charArr in rows {
for char in charArr {
result.append(char)
}
}
return String(result)
}
}
5. 最长回文子串
最长回文子串
中心扩散法
- 列举所有可能的回文子串的中心位置
- 中心位置可能是一个字符,也有可能是两个相邻的字符
- 记录最长回文子串的相关变量
class Solution {
func longestPalindrome(_ s: String) -> String {
guard s.count > 1 else {
return s
}
var index = 0
var left = 0
var right = 1
let arr = Array(s.utf8)
while index<s.count {
// 奇数
let len1 = findStr(s: arr, left: index, right: index)
// 偶数
let len2 = findStr(s: arr, left: index, right: index+1)
let len = max(len1, len2)
if len > right - left {
left = index-(len-1)/2
right = left + len
}
index = index + 1
}
let index1 = s.index(s.startIndex, offsetBy: left)
let index2 = s.index(s.startIndex, offsetBy: right)
return String(s[index1..<index2])
}
//aaaaaa index = 2 len 6 左移 2
//aaaaa index 2 len 5 左移2位
//babbd
//cbb
//cbbd
//babad
// 向两边扩散,
func findStr(s:[String.UTF8View.Element], left: Int,right: Int) -> Int {
var t_left = left
var t_right = right
while t_left>=0 ,t_right < s.count,s[t_left] == s[t_right] {
t_left = t_left - 1
t_right = t_right + 1
}
// 回文子串不包含left和right,所以回文子串的长度
return t_right - t_left - 1
}
}
动态规划法
思路
一个回文长度大于2,去掉两头以后,剩下的部分依然是回文
4. 寻找两个正序数组的中位数
class Solution {
func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double {
var arr = nums1 + nums2
arr.sort(by: >)
let m = arr.count/2
if arr.count%2 == 0 {
return (Double(arr[m]) + Double(arr[m-1]))/2
}else{
return Double(arr[m])
}
}
}
3. 无重复字符的最长子串
class Solution {
func lengthOfLongestSubstring(_ s: String) -> Int {
guard s.count > 1 else {
return s.count
}
var right = 1
var left = 0
var i = 0
var result = 1
let chars = Array(s.utf8)
while right < chars.count {
i = left
while i < right {
//用当前子串的最后一个,与前面每一个比较
if chars[right] == chars[i]{
left = i + 1
break
}
i = i + 1
}
result = max(result,right-left+1)
right = right + 1
}
return result
}
}
2. 两数相加
public class ListNode {
public var val: Int
public var next: ListNode?
public init() { self.val = 0; self.next = nil; }
public init(_ val: Int) { self.val = val; self.next = nil; }
public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; }
}
//输入:l1 = [2,4,3], l2 = [5,6,4]
//输出:[7,0,8]
//解释:342 + 465 = 807
class Solution {
func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? {
let header:ListNode = ListNode()
var t_nextNode:ListNode = header
var t = 0
var t_l1:ListNode? = l1
var t_l2:ListNode? = l2
while t_l1 != nil || t_l2 != nil {
if let t_t_l1 = t_l1 {
t = t + t_t_l1.val
t_l1 = t_t_l1.next
}
if let t_t_l2 = t_l2 {
t = t + t_t_l2.val
t_l2 = t_t_l2.next
}
t_nextNode.next = ListNode(t%10)
t_nextNode = t_nextNode.next!
t = t/10
//t = 1
//8 ,9 ,9,9 0, 0,,
}
if t > 0 {
t_nextNode.next = ListNode(t)
}
return header.next
}
}
1. 两数之和
查找表法
- 在遍历的同时,记录一些信息,以省去一层循环,以空间换时间
- 需要记录已经遍历过的数值和它所对应的下标,可以借助查找表实现
查找表有两个常用的实现:
哈希
平衡二叉树
eg: nums = [6,3,8,2,1] target=8
map key 6 3 8 2
value 0 1 2
6 :8-6= 2, 2不在,存0
3 :8-3= 5, 5不在,存1
8 :8-8= 0, 0不在,存2
2 :8-2= 6, 6在,输出0,3
class Solution {
/*
2,7,11,15 9
7:0
*/
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var dic:[Int:Int] = [:]
var index = 0
while index < nums.count{
let num = nums[index]
if dic[num] != nil {
return [dic[num]!,index]
}
dic[target-num] = index
index+=1
}
return [0,0]
}
}
字符串翻转,给定字符串“hello,world”,实现将其翻转。输出结果:"dlrow,olleh"
class Solution {
func reverse(_ str:String) -> String {
guard str.count > 1 else { return str }
var left = 0
var right = str.count - 1
var arr:[Character] = Array(str)
while left<right {
let temp = arr[right]
arr[right] = arr[left]
arr[left] = temp
left += 1;
right -= 1;
}
return String(arr)
}
}
17. 电话号码的字母组合
方法1:深度优先搜索
-关键字:所有组合
-模式识别: 搜索算法
自顶向下的递归实现深搜
定义子问题(原问题简化后的问题)
在当前递归层结合子问题结果解决原问题
eg: 2:abc 3 def
给定的数字是2和3
原问题就是 2和3 对应的所有字母组合
子问题 3 对应的字母组合
解就是 将2对应的字母组合 放在3的前面
递归定义
第一步:定义递归出口
第二步:递归解决子问题
第三步:解决原问题
最后 主函数生成辅助参数,调用递归
class Solution {
var result:[String] = []
func letterCombinations(_ digits: String) -> [String] {
guard digits.count>0 else {
return []
}
let phoneMap = [
"2":["a","b","c"],
"3":["d","e","f"],
"4":["g","h","i"],
"5":["j","k","l"],
"6":["m","n","o"],
"7":["p","q","r","s"],
"8":["t","u","v"],
"9":["w","x","y","z"],
]
self.solver(digits: digits, phoneMap: phoneMap)
return result;
}
func solver(digits:String,phoneMap:[String:[String]],index:Int = 0,resultStr:String = "") {
if index == digits.count{
self.result.append(resultStr)
return
}
let numbers = Array(digits)
let number = String(numbers[index])
let arr = phoneMap[number] ?? [];
for str in arr {
solver(digits: digits, phoneMap: phoneMap, index: index+1, resultStr: resultStr.appending(str))
}
}
}
17. 旋转数组
旋转的题,先写几个列子,找规律
class Solution {
func rotate(_ nums: inout [Int], _ k: Int) {
/*
1234
4321
3421
3412
*/
let kk = k % nums.count
reverse(&nums,left:0,right:nums.count-1)
reverse(&nums,left:0,right:kk-1)
reverse(&nums,left:kk,right:nums.count-1)
}
func reverse(_ nums:inout [Int], left:Int,right:Int){
var tl = left
var tr = right
while tl<tr{
let temp = nums[tl]
nums[tl] = nums[tr]
nums[tr] = temp
tl+=1
tr-=1
}
}
}
两个数组的交集 II
哈希映射
- 将个数小的数组,进行哈希映射
- key 值 vale 出现次数
遍历数组nums2
如果哈希存在,值为正,添加到结果里,值减一
class Solution {
func intersect(_ nums1: [Int], _ nums2: [Int]) -> [Int] {
var result:[Int] = []
let tnum = nums1.count <= nums2.count ? nums1 : nums2
let xnum = nums1.count <= nums2.count ? nums2 : nums1
var dic:[Int:Int] = [:]
for num in tnum{
dic[num] = (dic[num] != nil) ? (dic[num]! + 1) : 1
}
//[1:2]
for num in xnum {
if let t = dic[num],t>0 {
result.append(num)
dic[num] = t-1
}
}
return result
}
}
旋转图像
找规律
先上下交换
再左右交换
/*
13 14 15 16
9 10 11 12
5 6 7 8
1 2 3 4
*/
class Solution {
func rotate(_ matrix: inout [[Int]]) {
var i = 0
let lenght = matrix.count
while i < lenght/2 {
let t = matrix[i]
matrix[i] = matrix[lenght-1-i]
matrix[lenght-1-i] = t
i+=1
}
i = 0
while i < matrix.count {
var j = i+1
while j<matrix.count {
let t = matrix[i][j]
matrix[i][j] = matrix[j][i]
matrix[j][i] = t
j+=1
}
i+=1
}
}
}