scala练习——求数组的最长子数组长度

题目

给定一个数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。

子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组。

分析

需要计算子数组的最大长度,所以应该有一个数组变量来保存子数组;

为重复使用数组,可以引入变量index标记子数组下标;

为得到子数组的最大值,可以加入变量max保存其最大值;

双重嵌套循环,第一重循环决定从哪个数字开始,第二重循环向后遍历直到出现重复数字

代码

object Demo {
    def main(args: Array[String]): Unit = {
        println(maxLength(Array[Int](1,2,3,4,5,2,3,6,7,1,8,9)))
    }
    //计算数组的最长子数组长度
    def maxLength(arr: Array[Int]): Int = {
        //数组长度为1,则直接返回
        if (arr.length == 1) return 1
        //保存最长子数组长度
        var max = 0
        //保存子数组
        val subarray = new ArrayBuffer[Int]()
        for(i <- 0 until arr.length) {
            breakable{
                for(j <- i until arr.length) {
  					//确认是否出现重复数字
                    if (subarray.contains(arr(j))) {
                        //出现重复数字,判断子数组长度是否比max大
                        max = if (subarray.length  > max) subarray.length else max
                        println(subarray.mkString("[",",","]"))
                        //将子数组清空
                        subarray.remove(0,subarray.length)
                        //跳出循环
                        break
                    } else {
                        //未出现重复数字,将数字加入到子数组中
                        subarray += arr(j)
                    }
                }
            }
        }
        return max
    }

}

结果
在这里插入图片描述

优化

观察结果,第一次遍历到第三次的遍历明显重复多余,在得知数字重复时,应该更改循环变量,从重复数字的后一位开始遍历,这样就可以在一个循环中完成。同时当遍历到数组的最后一位时可以停止遍历了。

引入数组变量index保存子数组的每个数字的下标,

优化后代码

	def maxLength(arr:Array[Int]) : Int = {
        //数组长度为1,则直接返回
        if (arr.length == 1) return 1
        var max = 0
        val subarray = new ArrayBuffer[Int]()
        //保存子数组中的每个数字下标
        val index = new ArrayBuffer[Int]()
        var i = 0
        while (i < arr.length) {
            if (subarray.contains(arr(i)) ) {
				//出现重复的数字
                println(subarray.mkString("[",",","]"))
                //将子数组长度与max比较,得到最大值
                max = if (subarray.length > max) subarray.length else max
                //重置遍历的变量i,从重复数字的后一位开始遍历
                i = index(subarray.indexOf(arr(i))) + 1
                //清空子数组和下标数组
                subarray.remove(0,subarray.length)
                index.remove(0,index.length)
                println(s" i --> $i")
            } else {
                //数字与子数组中数字不重复,添加到子数组
                subarray += arr(i)
                //保存该数字在数组中的下标
                index += i
                i += 1
            }
            if (i == arr.length) {
                max = if (subarray.length > max) subarray.length else max
                println(subarray.mkString("[",",","]"))
            }
        }
        return max
    }

结果
在这里插入图片描述

思考

当数组很长时,子数组和下标数组可能会占用很大的内存,并且在arr.contains()的底层中应该也是遍历判断元素是否存在的,所以遍历时间应该差不多。为节省内存,可以将数组下标作为指针,遍历数组。

引入变量head标记子数组开始位置,tail标记子数组结尾位置,以循环遍历确定是否出现重复数字。

改进代码

	def maxLength(arr:Array[Int]) : Int = {
        //数组长度为1,则直接返回
        if (arr.length == 1) return 1
        var max = 0
        //子数组的头
        var head = 0
        //子数组的尾
        var tail = 1
        //遍历变量
        var i = 1
        while(i < arr.length) {
            var j = head
            var isRepeat = false
            //循环遍历,确定数字是否重复
            breakable {
                while (j < tail) {
                    if (arr(j) == arr(i)) {
                        println(s" head : $head   tail : $tail")
                        //数字出现重复
                        isRepeat = true
                        //比较max和子数组长度,得到最大值
                        max = if (max < (tail - head )) (tail - head ) else max
                        //重置遍历变量i
                        i = j + 1
                        //重置子数组的开始位置和结束位置
                        head = i
                        tail = i
                        //出现重复直接跳出循环
                        break
                    }
                    //当前位置的数字不重复,后移一位,开始下一次判断
                    j += 1
                }
            }
            //未出现重复数字
            if (!isRepeat) {
                //子数组向后移动一位
                tail += 1
                //遍历变量后移一位,开始下一次循环
                i += 1
            }
            //子数组已经移动到最后一位,且子数组中所有的数字都不重复
            if (i == arr.length) {
                println(s" last  head : $head   tail : $tail")
                //比较max和子数组长度,得到最大值
                max = if (max < (tail - head )) (tail - head) else max
            }
        }
        max
    }

结果
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值