16. 最接近的三数之和

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。
返回这三个数的和。假定每组输入只存在唯一答案。
示例:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
提示:
3 <= nums.length <= 10^3
-10^3 <= nums[i] <= 10^3
-10^4 <= target <= 10^4

  • 解题

fun _0016_threeSumClosest() {
println("--------_0016_threeSumClosest-------")
println(threeSumClosest(intArrayOf(-1, 2, 1, -4), 1))
println(threeSumClosest(intArrayOf(-1, -2, 2, 1, -4), 1))
println(threeSumClosest(intArrayOf(2, 1, -4), 1))
}

fun threeSumClosest(nums: IntArray?, target: Int): Int {
if (nums == null || nums.size < 3) return 0
var result = nums[0] + nums[1] + nums[2]
Arrays.sort(nums)
for (i in 0..nums.size - 2) {
var start = i + 1
var end = nums.size - 1
while (start < end) {
val sum = nums[i] + nums[start] + nums[end]
if (sum > target) {
end--
} else {
start++
}
if (abs(sum - target) < abs(result - target)) {
result = sum
}
}
}
return result
}

17. 电话号码的字母组合(九宫格键盘)

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例:
输入:"23"
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

  • 解题

fun _0017_letterCombinations() {
println("--------_0017_letterCombinations-------")
println(letterCombinations("23"))
println(letterCombinations("13"))
println(letterCombinations("333"))
}

/**
* 在遍历 digits 中所有的数字时,先建立一个临时的字符串数组t,通过数字到 dict 中取出字符串 str,
* 然后遍历取出字符串中的所有字符,再遍历当前结果 res 中的每一个字符串,将字符加到后面,并加入到临时字符串数组t中。
* 取出的字符串 str 遍历完成后,将临时字符串数组赋值给结果 res,具体实现参见代码如下:
*/
fun letterCombinations(digits: String?): ArrayList<String> {
if (digits == null || digits.isEmpty()) return ArrayList()
val dict = arrayListOf("0", "1", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz")
var res = arrayListOf("")
for (i in digits.indices) {
val t = ArrayList<String>()
val str = dict[digits[i] - '0']
for (j in str.indices) {
for (s in res) {
t.add(s + str[j])
}
}
res = t
}
return res
}

18. 四数之和

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,
使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]

  • 解题

fun _0018_fourSum() {
println("--------_0018_fourSum-------")
println(fourSum(intArrayOf(1, 0, -1, 0, -2, 2), 0))
}

fun fourSum(nums: IntArray?, target: Int): List<List<Int>> {
if (nums == null || nums.size < 4) return ArrayList()
val res = ArrayList<List<Int>>()
val n = nums.size
Arrays.sort(nums)
for (i in 0..n - 3) {
if (i > 0 && nums[i] == nums[i - 1]) continue
for (j in i + 1..n - 2) {
if (j > i + 1 && nums[j] == nums[j - 1]) continue
var left = j + 1
var right = n - 1
while (left < right) {
val sum = nums[i] + nums[j] + nums[left] + nums[right]
if (sum == target) {
val oneResult = arrayListOf(nums[i], nums[j], nums[left], nums[right])
res.add(oneResult)
while (left < right && nums[left] == nums[left + 1]) left++
while (left < right && nums[right] == nums[right - 1]) right--
left++
right--
} else if (sum < target) {
left++
} else right--
}
}
}
return res
}

19. 删除链表的倒数第N个节点

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗

  • 解题

fun _0019_removeNthFromEnd() {
println("--------_0019_removeNthFromEnd-------")
removeNthFromEnd(ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5))))), 1)?.print()
removeNthFromEnd(ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5))))), 2)?.print()
removeNthFromEnd(ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5))))), 3)?.print()
removeNthFromEnd(ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5))))), 4)?.print()
removeNthFromEnd(ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5))))), 5)?.print()

}

/**
* 这道题让我们移除链表倒数第N个节点,限定n一定是有效的,即n不会大于链表中的元素总数。
* 还有题目要求一次遍历解决问题,那么就得想些比较巧妙的方法了。比如首先要考虑的时,如何找到倒数第N个节点,
* 由于只允许一次遍历,所以不能用一次完整的遍历来统计链表中元素的个数,而是遍历到对应位置就应该移除了。
* 那么就需要用两个指针来帮助解题,pre 和 cur 指针。首先 cur 指针先向前走N步,如果此时 cur 指向空,
* 说明N为链表的长度,则需要移除的为首元素,那么此时返回 head->next 即可,如果 cur 存在,再继续往下走,
* 此时 pre 指针也跟着走,直到 cur 为最后一个元素时停止,此时 pre 指向要移除元素的前一个元素,
* 再修改指针跳过需要移除的元素即可
*/
fun removeNthFromEnd(head: ListNode?, n: Int): ListNode? {
if (head?.next == null) return null
var n = n
var pre = head
var cur = head
for (i in 0 until n) {
cur = cur?.next
}
if (cur == null) return head.next //说明n为链表长度
while (cur?.next != null) {
cur = cur.next
pre = pre?.next
}
pre?.next = pre?.next?.next
return head
}

20. 有效的括号

给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: "()"
输出: true
示例 2:
输入: "()[]{}"
输出: true
示例 3:
输入: "(]"
输出: false
示例 4:
输入: "([)]"
输出: false
示例 5:
输入: "{[]}"
输出: true

  • 解题

fun _0020_isValid() {
println("--------_0020_isValid-------")
println(isValid("()"))
println(isValid("()[]{}"))
println(isValid("(]"))
println(isValid("{[]}"))
}

/**
* 这里需要用一个栈,开始遍历输入字符串,如果当前字符为左半边括号时,则将其压入栈中,如果遇到右半边括号时,
* 若此时栈为空,则直接返回 false,如不为空,则取出栈顶元素,若为对应的左半边括号,则继续循环,反之返回 false,代码如下:
*/
fun isValid(s: String): Boolean {
val stack = Stack<Char>()
for (i in s.indices) {
val c = s[i]
if (c == '(' || c == '{' || c == '[')
stack.push(c)
else {
if (stack.isEmpty()) return false
if (c == ')' && stack.peek() != '(') return false
if (c == ']' && stack.peek() != '[') return false
if (c == '}' && stack.peek() != '{') return false
stack.pop()
}
}
return stack.isEmpty()
}
我是今阳,如果想要进阶和了解更多的干货,欢迎关注公众号”今阳说“接收我的最新文章