字符串反转
思路:双指针
func reverseString(_ s: inout [Character]) {
var left = 0
var right = s.count - 1
while left < right {
// 利用元组交换
(s[right],s[left]) = (s[left],s[right])
left += 1
right -= 1
}
}
链表反转
思路:头差法
func reverseList1(_ head: ListNode?) -> ListNode? {
var pre: ListNode?
var head = head
while head != nil {
let next = head!.next;
head!.next = pre
pre = head
head = next
}
return pre
}
func reverseList2(_ head: ListNode?) -> ListNode? {
var p = head
// 反转后的链表头部
var newH:ListNode? = nil
// 遍历链表
while p != nil {
// 记录下个节点
let next = p!.next;
// 当前节点next指向新链表头部
p!.next = newH
// 更改链表头部为当前节点
newH = p
// 移动p指针
p = next
}
// 返回反转后的链表头节点
return newH
}
有序数组合并
思路:两个数组分别用指针遍历对比,放到新的数组
// 有序数组合并,注意的是合并到nums1,所以nums1是inout修饰
static func merge(_ nums1: inout [Int], _ m: Int, _ nums2: [Int], _ n: Int) {
let nums1copy = Array(nums1[0..<m])
var p1 = 0 // 指向nums1copy
var p2 = 0 // 指向nums2
var i = 0 // 执行num1
while p1 < m && p2 < n {
if nums1copy[p1] < nums2[p2] {
nums1[i] = nums1copy[p1]
p1 += 1
} else {
nums1[i] = nums2[p2]
p2 += 1
}
i += 1
}
while p1 < m {
nums1[i] = nums1copy[p1]
p1 += 1
i += 1
}
while p2 < n {
nums1[i] = nums2[p2]
p2 += 1
i += 1
}
}
static func merge1(_ nums1: inout [Int], _ m: Int, _ nums2: [Int], _ n: Int) {
var p1 = m - 1
var p2 = n - 1
var p = m + n - 1
while p1 >= 0 && p2 >= 0 {
if nums1[p1] < nums2[p2] {
nums1[p] = nums2[p2]
p -= 1
p2 -= 1
} else {
nums1[p] = nums1[p1]
p -= 1
p1 -= 1
}
}
// 这里要处理 num2 还有剩余的情况,因为num1保证有足够空间容纳num2, 因为 m <= n
while p2 >= 0 {
nums1[p] = nums2[p2]
p2 -= 1
p -= 1
}
// 或者是这种写法
// if p2 >= 0 {
// nums1[0...p2] = nums2[0...p2]
// }
}
hash算法
func firstUniqChar(_ s: String) -> Character {
var target: Character = " "
// 第一次遍历,先把字符串每个字母出现次数,存到256的数组
var arr = Array(0..<256).map { _ in return 0}
for c in s {
if let ascii = c.asciiValue {
let idx = Int(ascii)
arr[idx] += 1
}
}
// 从头遍历存储的数组,找到第一个为1的字符
for c in s {
if let ascii = c.asciiValue {
let idx = Int(ascii)
if arr[idx] == 1 {
target = c
break
}
}
}
return target
}
查找两个子视图的共同父视图
//找到view1的所有父视图
UIView *view1;
NSMutableArray *arr1 = [NSMutableArray array];
UIView *temp = view1;
while (temp.superview) {
[arr1 addObject:temp.superview];
temp = temp.superview;
}
//找到view2的所有父视图
UIView *view2;
NSMutableArray *arr2 = [NSMutableArray array];
temp = view2;
while (temp.superview) {
[arr2 addObject:temp.superview];
temp = temp.superview;
}
//开始查找---> 倒序遍历,因为他们的最顶端的父视图肯定都是UIWindow
int i = 0;
NSMutableArray *resultArr = [NSMutableArray array];//他们的共同父视图可能会有好多个
while (i < MIN(arr1.count, arr2.count)) {
//取最后一个父视图
UIView *super1 = arr1[arr1.count - i -1];
UIView *super2 = arr2[arr2.count - i -1];
if (super1 == super2)
{
[resultArr addObject:super1];
i ++;
}
else//不相等说明已经没有共同的父视图了
{
break;
}
}
求无序数组当中的中位数
/*
解法一: 先排序后取中位数
解法二: 利用快排思想, 效率最优
[12,3,10,8,6,7,11,13,9]
*/
static func findMedian(arr: inout [Int]) -> Int {
//使用快排思想,任意挑选一个元素,以该元素为支点,划分集合为两部分。
//如果左侧集合的长度==(n-1)/2,那么支点就是中位数。
//如果左侧集合的长度<(n-1)/2,那么中位数在右侧,反之,中位数载左侧。
let i = 0
let j = arr.count - 1
let mid = (arr.count - 1) / 2
var div = partSort1(arr: &arr, start: i, end: j)
while div != mid {
if mid < div {
div = partSort1(arr: &arr, start: i, end: div - 1)
} else {
div = partSort1(arr: &arr, start: div + 1, end: j)
}
}
return arr[mid]
}
static func partSort(arr: inout [Int], start: Int, end: Int) -> Int {
var i = start
var j = end
//选取关键字
let key = arr[j]
while i < j {
//左边找比key大的值
while i < j && arr[i] <= key {
i += 1
}
//右边找比key小的值
while i < j && arr[j] >= key {
j -= 1
}
if i < j {
//找到之后交换左右的值
let temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
}
}
// j在中间位置,把key的值放到j的位置交换, 左边比key小,右边比key大
let temp = arr[j]
arr[j] = arr[end]
arr[end] = temp
// 这里return j 和 i 是一样的
return j
}
二分查找
func binarySearch<T: Comparable>(_ a: [T], key: T, range: Range<Int>) -> Int? {
if range.lowerBound >= range.upperBound {
// If we get here, then the search key is not present in the array.
return nil
} else {
// Calculate where to split the array.
let midIndex = range.lowerBound + (range.upperBound - range.lowerBound) / 2
// Is the search key in the left half?
if a[midIndex] > key {
return binarySearch(a, key: key, range: range.lowerBound ..< midIndex)
// Is the search key in the right half?
} else if a[midIndex] < key {
return binarySearch(a, key: key, range: midIndex + 1 ..< range.upperBound)
// If we get here, then we've found the search key!
} else {
return midIndex
}
}
}
func binarySearch<T: Comparable>(_ a: [T], key: T) -> Int? {
var lowerBound = 0
var upperBound = a.count
while lowerBound < upperBound {
let midIndex = lowerBound + (upperBound - lowerBound) / 2
if a[midIndex] == key {
return midIndex
} else if a[midIndex] < key {
lowerBound = midIndex + 1
} else {
upperBound = midIndex
}
}
return nil
}
总结
- 高频: 链表反转, 查找两个子视图的共同父视图