不定期持续更新
1.给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var index = 0
while index < nums.count {
let num = target - nums[index]
let numIndex:Int = nums.firstIndex(of: num) ?? -1
if numIndex >= 0 && numIndex != index {
return [index,numIndex]
}
index += 1
}
return []
}
2.给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? {
let result = ListNode(0)
var tempResult = result;
var templ1 = l1
var templ2 = l2
var addOne:Bool = false
while templ1 != nil || templ2 != nil {
if (templ1 != nil) {
tempResult.val += (templ1?.val)!
templ1 = templ1?.next
}
if (templ2 != nil) {
tempResult.val += (templ2?.val)!
templ2 = templ2?.next
}
if addOne {
tempResult.val += 1
}
if tempResult.val >= 10 {
tempResult.val = tempResult.val%10
addOne = true
}else{
addOne = false
}
if templ1 != nil || templ2 != nil{
tempResult.next = ListNode(0);
tempResult = tempResult.next!;
}else{
if addOne{
tempResult.next = ListNode(1);
}
}
}
return result;
}
3.给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
/* 本题我自己的解题方式超时,不过能得到答案。swift 能更优的解题如下
func lengthOfLongestSubstring(_ s: String) -> Int {
let string = s.utf8CString
var result = 0
var map = [CChar: Int](minimumCapacity: Int(Int8.max))
var start = 0
for index in 0...string.count - 1{
let c = string[index]
if c != 0 {
if let last = map[c],last >= start{
start = last + 1
}else if result < index - start + 1{
result = index - start + 1
}
map[c] = index
}
}
return result
}
*/
func lengthOfLongestSubstring(_ s: String) -> Int {
if s.count == 1 {
return 1;
}
var maxCount:Int = 0
var index:Int = 0
while index < s.count {
let tempStr = s.substring(to: s.index(s.startIndex, offsetBy: index + 1))
let tempStr1 = s.substring(from: s.index(s.startIndex, offsetBy: index + 1));
var have = false
var remTempStr = tempStr
while remTempStr.count != 0{
var charStr = remTempStr.remove(at: remTempStr.index(remTempStr.startIndex, offsetBy: 0))
let charString = String(charStr);
let rang = remTempStr.range(of:charString)
if rang != nil {
have = true;
}
}
if have == false {
maxCount = max(maxCount, tempStr.count)
}
if tempStr1.count > maxCount {
maxCount = max(maxCount, self.lengthOfLongestSubstring(tempStr1))
}
index += 1
}
return maxCount;
}
4.给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double {
var nums = nums1 + nums2;
nums.sort()
if nums.count % 2 == 0 {
return Double((nums[nums.count/2] + nums[nums.count/2 - 1])) / 2
}else{
return Double(nums[(nums.count + 1)/2 - 1])
}
}
5.给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
这题原本我用OC暴力方法解出来了。但是转swift超时,然后用LeetCode给的解法写了一个发现也超时。
OC 解法
-(NSString *)longestPalindrome2:(NSString *)s{
if (s.length == 1 || s.length == 0) {
return s;
}
NSString * maxString = [s substringWithRange:NSMakeRange(0, 1)];
NSMutableArray *compareCharArray = [NSMutableArray array];
for (int i = 0; i < s.length; i++) {
NSString * charStr = [s substringWithRange:NSMakeRange(i, 1)];
if ([compareCharArray indexOfObject:charStr] == NSNotFound) {
NSArray * compareArray = [s componentsSeparatedByString:charStr];
NSMutableString * compareStr = [[NSMutableString alloc] init];
for (int j = 0;j < compareArray.count ;j++) {
NSString *tempStr = [compareArray objectAtIndex:j];
if (j > 0) {
[compareStr appendString:charStr];
}
if (tempStr.length > 0) {
[compareStr appendString:tempStr];
}
if (j != compareArray.count - 1) {
[compareStr appendString:charStr];
}
if (compareStr.length > 0
&& [s rangeOfString:compareStr].location != NSNotFound
&& compareStr.length > maxString.length
&& [self checkString:compareStr]) {
maxString = [compareStr copy];
}
for (int k = j + 1; k < compareArray.count; k++) {
tempStr = [compareArray objectAtIndex:k];
if (tempStr.length > 0) {
[compareStr appendString:tempStr];
}
if (k != compareArray.count - 1) {
[compareStr appendString:charStr];
}
if (compareStr.length > 0
&& [s rangeOfString:compareStr].location != NSNotFound
&& compareStr.length > maxString.length
&& [self checkString:compareStr]) {
maxString = [compareStr copy];
}
if (k == compareArray.count - 1) {
[compareStr replaceCharactersInRange:NSMakeRange(0, compareStr.length) withString:@""];
}
}
}
[compareCharArray addObject:charStr];
}
}
return maxString;
}
-(BOOL)checkString:(NSString *)string{
NSMutableString *compareStr1 = [[NSMutableString alloc] init];
for (NSInteger k = string.length - 1; k >= 0; k--) {
[compareStr1 appendString:[string substringWithRange:NSMakeRange(k, 1)]];
}
if ([string isEqualToString:compareStr1]) {
return YES;
}
return NO;
}
swift 解法
func longestPalindrome(_ s: String) -> String {
if s.count == 1 || s.count == 0 {
return s
}
var start: Int = 0
var end: Int = 0
for i in 0..<s.count {
let len1: Int = expandAroundCenter(s, left: i, right: i)
let len2: Int = expandAroundCenter(s, left: i, right: i + 1)
let len: Int = max(len1, len2)
if len > end - start {
start = i - (len - 1) / 2
end = i + len / 2
}
}
return (s as NSString).substring(with: NSMakeRange(start, end + 1 - start)) as String
}
func expandAroundCenter(_ s: String?, left: Int, right: Int) -> Int {
var L: Int = left
var R: Int = right
while L >= 0 && R < s?.count ?? 0 && (s! as NSString).character(at: L) == (s! as NSString).character(at: R) {
L -= 1
R += 1
}
return R - L - 1
}
6.将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “LEETCODEISHIRING” 行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“LCIRETOESIIGEDHN”。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
func convert(_ s: String, _ numRows: Int) -> String {
let array:NSMutableArray = NSMutableArray()
for i in 0..<s.count {
var line = 1
if numRows > 2 {
line = (i+1)%(numRows + numRows - 2)
if line == 0 {
line = 2
}
if line > numRows{
line = numRows - (line - numRows)
}
}else{
line = (i%numRows) + 1
}
let charStr = (s as NSString).substring(with: NSMakeRange(i, 1))
if array.count != numRows {
array.add(charStr)
}else{
var string = array.object(at: line - 1)
string = (string as! String) + (charStr as String)
array.replaceObject(at: line - 1, with: string)
}
}
return array.componentsJoined(by: "")
}
7.给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
func reverse(_ x: Int) -> Int {
let string:String = String.init(x)
var reverseStr:String = String()
for i in 0 ..< string.count {
let charStr = (string as NSString).substring(with: NSMakeRange(string.count - 1 - i, 1))
if charStr == "-" {
reverseStr = charStr + reverseStr
}else{
reverseStr.append(charStr)
}
}
var num = (reverseStr as NSString).integerValue
if num > Int32.max || num < Int32.min {
num = 0
}
return num
}
8.请你来实现一个 atoi 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。
说明:
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,qing返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
func myAtoi(_ str: String) -> Int {
var numStr = ""
for i in 0..<str.count {
let charStr = (str as NSString).substring(with: NSMakeRange(i, 1))
if charStr != " "{
if numStr.count == 0{
if charStr == "+" || charStr == "-" || charStr == "0" || (charStr as NSString).integerValue > 0{
numStr = charStr
}else {
break
}
}else{
if (charStr as NSString).integerValue > 0 || charStr == "0"{
numStr = numStr + charStr
}else{
break
}
}
}else{
if numStr.count > 0 {
break
}
}
}
var num = (numStr as NSString).integerValue
if num > Int32.max {
num = Int(Int32.max)
}
if num < Int32.min {
num = Int(Int32.min)
}
return num
}
9.判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
func isPalindrome(_ x: Int) -> Bool {
if x < 0 {
return false
}
let string:String = String.init(x)
var newString = ""
for i in 0..<string.count {
newString += (string as NSString).substring(with: NSMakeRange(string.count - 1 - i, 1))
}
return (newString as NSString).integerValue == x
}
10.给定一个字符串 (s) 和一个字符模式 §。实现支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
‘.’ 匹配任意单个字符。
‘*’ 匹配零个或多个前面的元素。
匹配应该覆盖整个字符串 (s) ,而不是部分字符串。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
备注:个人感觉官网这题有问题,下面是能过的解法。
func isMatch(_ s: String, _ p: String) -> Bool {
let sArray = Array(s), pArray = Array(p)
/*解析:首先 s可以为空的*/
var rec: [[Bool]] = Array(repeating: Array(repeating: false, count: pArray.count + 1), count: sArray.count + 1)
rec[0][0] = true
for i in 0..<pArray.count {
if pArray[i] == "*" {
rec[0][i + 1] = rec[0][i - 1]
}
}
for i in 0..<sArray.count {
for j in 0..<pArray.count {
if pArray[j] != "*" {
if rec[i][j] {
if pArray[j] == "." || pArray[j] == sArray[i] {
rec[i + 1][j + 1] = true
}
}
} else {
if rec[i + 1][j - 1] {
rec[i + 1][j + 1] = true
} else if rec[i][j - 1] || rec[i][j + 1] {
if pArray[j - 1] == sArray[i] || pArray[j - 1] == "." {
rec[i + 1][j + 1] = true
}
}
}
}
}
return rec[s.count][p.count]
}
11. 盛最多水的容器
给定 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
func maxArea(_ height: [Int]) -> Int {
/*暴力方法
var maxAreaValue = 0
for i in 1 ..< height.count {
for j in 0..<i{
var value = height[i]
if height[i] > height[j]{
value = height[j]
}
if value * (i - j) > maxAreaValue{
maxAreaValue = value * (i - j)
}
}
}
return maxAreaValue*/
//比较少的计算量
var ans = 0
var i = 0
var j = height.count - 1
while i < j {
let h1 = height[i]
let h2 = height[j]
let area = abs(i - j) * min(h1, h2)
ans = max(ans, area)
if h1 < h2 {
i += 1
}
else {
j -= 1
}
}
return ans
}
12. 整数转罗马数字
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。
func intToRoman(_ num: Int) -> String {
let char = ["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"]
let nums = [1000,900,500,400,100,90,50,40,10,9,5,4,1]
var romanStr = ""
var value = num
for i in 0..<nums.count{
if value >= nums[i] {
let count = value/nums[i]
for _ in 0..<count {
romanStr += char[i]
}
value = value%nums[i]
if value == 0 {
break
}
}
}
return romanStr
}
13. 罗马数字转整数
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
func romanToInt(_ s: String) -> Int {
let char = ["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"]
let nums = [1000,900,500,400,100,90,50,40,10,9,5,4,1]
var romanStr = s
var value = 0
while romanStr.count != 0 {
for i in 0..<char.count {
if (romanStr as NSString).hasPrefix(char[i]){
value += nums[i]
romanStr = (romanStr as NSString).substring(from: (char[i] as NSString).length)
break
}
}
}
return value;
}
14.编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
func longestCommonPrefix(_ strs: [String]) -> String {
if strs.count == 0 {
return ""
}
let string = strs[0]
var prefixStr = ""
var broken = false
for i in 0..<string.count {
let temPreStr = (string as NSString).substring(to: i+1)
for tempStr in strs {
if !((tempStr as NSString).hasPrefix(temPreStr)){
broken = true
break
}
}
if broken {
break
}else{
prefixStr = temPreStr
}
}
return prefixStr
}
15.给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
func threeSum(_ nums: [Int]) -> [[Int]] {
var nums = nums.sorted()
var result = [[Int]]()
for i in 0..<nums.count {
if i == 0 || i > 0 && nums[i] != nums[i-1] {
var left = i + 1, right = nums.count - 1
let sum = 0 - nums[i]
while left < right {
if nums[left] + nums[right] == sum {
result.append([nums[left], nums[right], nums[i]])
while left < right && nums[left] == nums[left + 1]{
left += 1
}
while left < right && nums[right] == nums[right - 1]{
right -= 1
}
left += 1
right -= 1
} else if nums[left] + nums[right] < sum {
left += 1
} else {
right -= 1
}
}
}
}
return result
}
16. 最接近的三数之和
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
func threeSumClosest(_ nums: [Int], _ target: Int) -> Int {
if nums.count < 3 {
return 0
}
var tempNums = nums
tempNums.sort() //数字先排序
var closestNum = tempNums[0] + tempNums[1] + tempNums[2]
if tempNums.count > 3 {
for f in 0 ..< tempNums.count - 2 {
for s in (f + 1)..<tempNums.count - 1 {
for t in (s + 1)..<tempNums.count {
let threeNum = tempNums[f] + tempNums[s] + tempNums[t]
if abs(target - threeNum) < abs( target - closestNum) {
closestNum = threeNum
}
}
}
}
}
return closestNum
}
17. 电话号码的字母组合
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
func letterCombinations(_ digits: String) -> [String] {
if digits.count == 0 {
return []
}
let numsArray:[[String]] = [["a","b","c"],["d","e","f"],["g","h","i"],["j","k","l"],["m","n","o"],["p","q","r","s"],["t","u","v"],["w","x","y","z"]]
var strArray:[String] = []
for i in 0..<digits.count {
let charStr = (digits as NSString).substring(with: NSMakeRange(i, 1))//数字
let charArray:[String] = numsArray[(charStr as NSString).integerValue - 2]//数字代表 字符数组
var newStrArray:[String] = []
for char in charArray{
for str in strArray{
newStrArray.append(str+char)
}
if strArray.count == 0 {
newStrArray.append(char)
}
}
strArray = newStrArray
}
return strArray
}
18. 四数之和
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
(参考三数之和)
func fourSum(_ nums: [Int], _ target: Int) -> [[Int]] {
let count = nums.count
guard count >= 4 else { return [] }
let nums = nums.sorted()
var result = [[Int]]()
for i in 0..<count - 3 {
if i > 0 && nums[i] == nums[i - 1] {
continue
}
let threeSum = target - nums[i]
for j in i + 1..<count - 2 {
if j > i + 1 && nums[j] == nums[j - 1] {
continue
}
let twoSum = threeSum - nums[j]
var left = j + 1, right = count - 1
while left < right {
if nums[left] + nums[right] == twoSum {
result.append([nums[i], nums[j], nums[left], nums[right]])
while left < right && nums[left] == nums[left + 1] {
left += 1
}
while left < right && nums[right] == nums[right - 1] {
right -= 1
}
left += 1
right -= 1
} else if nums[left] + nums[right] < twoSum {
left += 1
} else {
right -= 1
}
}
}
}
return result
}